Рейки Об'єкт хешу


147

У мене є такий об’єкт, який створено

@post = Post.create(:name => 'test', :post_number => 20, :active => true)

Після того як це буде збережено, я хочу мати можливість повернути об'єкт у хеш, наприклад, роблячи щось подібне:

@object.to_hash

Як це можливо з рейок?

Відповіді:


296

Якщо ви шукаєте лише атрибути, ви можете отримати їх:

@post.attributes

30
Не використовуйте це під час циклу, Дорогий метод . Ідіть з as_json
AnkitG

5
.to_json
запитає

1
Працює з, joinsі select, Person.joins(:address).select("addresses.street, persons.name").find_by_id(id).attributesповернеться { street: "", name: "" }
fangxing

3
@AnkitG Я не вірю, що as_json є менш дорогим. Якщо ви подивитеся на вихідний код для as_json, він зателефонує, serializable_hashякий, у свою чергу, зателефонує attributes! Тож ваша порада насправді додає два шари складності attributes, роблячи це ще дорожчим.
sandre89

2
.as_jsonбуде серіалізувати об’єкт на рубіновий хеш
roadev

45

В останній версії Rails (не вдається точно сказати, який саме), ви можете використовувати as_jsonметод:

@post = Post.first
hash = @post.as_json
puts hash.pretty_inspect

Виведе:

{ 
  :name => "test",
  :post_number => 20,
  :active => true
}

Щоб піти трохи далі, ви можете змінити цей метод, щоб налаштувати спосіб відображення ваших атрибутів, зробивши щось подібне:

class Post < ActiveRecord::Base
  def as_json(*args)
    {
      :name => "My name is '#{self.name}'",
      :post_number => "Post ##{self.post_number}",
    }
  end
end

Тоді з тим самим екземпляром, що і вище, буде виводитися:

{ 
  :name => "My name is 'test'",
  :post_number => "Post #20"
}

Звичайно, це означає, що ви повинні чітко вказати, які атрибути повинні з'являтися.

Сподіваюся, це допомагає.

Редагувати:

Також ви можете перевірити дорогоцінний камінь Hashifiable .


ОП не просив JSON, а хеш.
Девід Хемпі

5
@DavidHempy Будь ласка, уважно прочитайте мою відповідь перед тим, як відмовитись. Як показано в моїх прикладах, саме це робить #as_json і призначений для: api.rubyonrails.org/classes/ActiveModel/Serializers/… . Я не вибрав назву цього методу.
Раф

25
@object.as_json

as_json має дуже гнучкий спосіб налаштування складного об'єкта відповідно до модельних відносин

ПРИКЛАД

Модельна кампанія належить до магазину і має один список

У списку моделей багато list_tasks і кожен з list_tasks має багато коментарів

Ми можемо отримати один json, який легко поєднує всі ці дані.

@campaign.as_json(
    {
        except: [:created_at, :updated_at],
        include: {
            shop: {
                except: [:created_at, :updated_at, :customer_id],
                include: {customer: {except: [:created_at, :updated_at]}}},
            list: {
                except: [:created_at, :updated_at, :observation_id],
                include: {
                    list_tasks: {
                        except: [:created_at, :updated_at],
                        include: {comments: {except: [:created_at, :updated_at]}}
                    }
                }
            },
        },
        methods: :tags
    })

Способи сповіщення :: теги можуть допомогти вам приєднати будь-який додатковий об’єкт, який не має стосунків з іншими. Вам просто потрібно визначити метод з тегами імен у модельній кампанії . Цей метод повинен повернути все, що вам потрібно (наприклад, Tags.all)

Офіційна документація на as_json


Була зроблена спеціальна функція безпосередньо перед тим, як знайти її. Хотів більше методу одноразового використання, а не визначення функції для класу. Пропустили це навіть після роботи з методами серіалізації XML чомусь. to_Варіант , здається, працює майже точно так же , як as_варіант, для цитованого виходу за винятком. Єдине, що мені не сподобалось, - це не збереження порядку моїх критеріїв фільтра. Здається, це в алфавітному порядку відсортовано. Я думав, що це пов’язано з чудовим коштом, який я маю в своєму оточенні, але я не думаю, що це так.
Pysis

8

Ви можете отримати атрибути об'єкта моделі, повернуті як хеш, використовуючи будь-який

@post.attributes

або

@post.as_json

as_jsonдозволяє включати асоціації та їх атрибути, а також вказувати, які атрибути включати / виключати (див. документацію ). Однак якщо вам потрібні лише атрибути базового об’єкта, тестування в моєму додатку з рубіном 2.2.3 та рейками 4.2.2 демонструє, що attributesпотрібно менше половини стільки часу, скільки as_json.

>> p = Problem.last
 Problem Load (0.5ms)  SELECT  "problems".* FROM "problems"  ORDER BY "problems"."id" DESC LIMIT 1
=> #<Problem id: 137, enabled: true, created_at: "2016-02-19 11:20:28", updated_at: "2016-02-26 07:47:34"> 
>>
>> p.attributes
=> {"id"=>137, "enabled"=>true, "created_at"=>Fri, 19 Feb 2016 11:20:28 UTC +00:00, "updated_at"=>Fri, 26 Feb 2016 07:47:34 UTC +00:00}
>>
>> p.as_json
=> {"id"=>137, "enabled"=>true, "created_at"=>Fri, 19 Feb 2016 11:20:28 UTC +00:00, "updated_at"=>Fri, 26 Feb 2016 07:47:34 UTC +00:00}
>>
>> n = 1000000
>> Benchmark.bmbm do |x|
?>   x.report("attributes") { n.times { p.attributes } }
?>   x.report("as_json")    { n.times { p.as_json } }
>> end
Rehearsal ----------------------------------------------
attributes   6.910000   0.020000   6.930000 (  7.078699)
as_json     14.810000   0.160000  14.970000 ( 15.253316)
------------------------------------ total: 21.900000sec

             user     system      total        real
attributes   6.820000   0.010000   6.830000 (  7.004783)
as_json     14.990000   0.050000  15.040000 ( 15.352894)

as_json знову зателефонує на запит до бази даних, якщо ви користуєтеся вкладеною resouce із методом приєднання
Tony Hsieh

6

Тут є кілька чудових пропозицій.

Я думаю, що варто відзначити, що ви можете ставитися до моделі ActiveRecord як хеш так:

@customer = Customer.new( name: "John Jacob" )
@customer.name    # => "John Jacob"
@customer[:name]  # => "John Jacob"
@customer['name'] # => "John Jacob"

Тому замість генерування атрибутів хеша, ви можете використовувати сам об’єкт як хеш.


6

Ви можете однозначно використовувати атрибути для повернення всіх атрибутів, але ви можете додати метод екземпляра до Post, назвати його "to_hash" і дати йому повернути потрібні дані в хеші. Щось на зразок

def to_hash
 { name: self.name, active: true }
end

2

не впевнений, що це те, що вам потрібно, але спробуйте це в рубіновій консолі:

h = Hash.new
h["name"] = "test"
h["post_number"] = 20
h["active"] = true
h

очевидно, це поверне вам хеш-консоль. якщо ви хочете повернути хеш із методу - замість просто "h", спробуйте скористатися "return h.inspect", щось подібне до:

def wordcount(str)
  h = Hash.new()
  str.split.each do |key|
    if h[key] == nil
      h[key] = 1
    else
      h[key] = h[key] + 1
    end
  end
  return h.inspect
end

Плакат розпитує про моделі ActiveRecord в Rails.
Джефрі Харрінгтон


0

Відповідь Свананда чудова.

якщо ви використовуєте FactoryGirl, ви можете використовувати його buildметод для генерації хеша атрибута без ключа id. напр

build(:post).attributes

0

Старе питання, але з великим посиланням ... Я думаю, що більшість людей використовують інші методи, але існує інфактний to_hashметод, він повинен бути налаштований правильно. Взагалі, вищип - це краща відповідь після рейки 4 ... відповідь на це головним чином тому, що мені довелося шукати купу, щоб знайти цю нитку або щось корисне, і якщо припустити, що інші стикаються з тією ж проблемою ...

Примітка: рекомендувати це не всім, але кращі випадки!


З рубіну на рейках ... http://api.rubyonrails.org/classes/ActiveRecord/Result.html ...

This class encapsulates a result returned from calling #exec_query on any database connection adapter. For example:

result = ActiveRecord::Base.connection.exec_query('SELECT id, title, body FROM posts')
result # => #<ActiveRecord::Result:0xdeadbeef>

...

# Get an array of hashes representing the result (column => value):
result.to_hash
# => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
      {"id" => 2, "title" => "title_2", "body" => "body_2"},
      ...
     ] ...
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.