Получить атрибуты всей ассоциации модели AR?

Что Вы думаете, что самый оптимальный путь состоит в том, чтобы получить все атрибуты для всех ассоциаций, которые имеет модель AR?

т.е.: скажем, у нас есть модель Target.

class Target < ActiveRecord::Base
  has_many :countries
  has_many :cities
  has_many :towns
  has_many :colleges
  has_many :tags

  accepts_nested_attributes_for :countries, :cities, ...
end

Я хотел бы получить атрибуты всей ассоциации путем вызова метода на Целевом экземпляре:

target.associations_attributes
>> { :countries => { "1" => { :name => "United States", :code => "US", :id => 1 }, 
                     "2" => { :name => "Canada", :code => "CA", :id => 2 } },
     :cities => { "1" => { :name => "New York", :region_id => 1, :id => 1 } },
     :regions => { ... },
     :colleges => { ... }, ....
   }

В настоящее время я делаю эту работу путем итерации на каждой ассоциации, и затем на каждой модели ассоциации, Но это довольно дорого, Как Вы думаете, что я могу оптимизировать это?

Просто примечание: Я понял, что Вы не можете звонить target.countries_attributes на has_many связи с nested_attributes, one_to_one ассоциации позволяют звонить target.country_attributes

8
задан jpemberthy 16 August 2017 в 05:01
поделиться

1 ответ

Я не понимаю, что вы имеете в виду под итерацией для всех ассоциаций. Вы уже используете отражения?

По-прежнему любопытно, есть ли более аккуратный способ, но это то, что я мог придумать, что более или менее приводит к хэшу, который вы показываете в своем примере:

class Target < ActiveRecord::Base
  has_many :tags

  def associations_attributes
    # Get a list of symbols of the association names in this class
    association_names = self.class.reflect_on_all_associations.collect { |r| r.name }
    # Fetch myself again, but include all associations
    me = self.class.find self.id, :include => association_names
    # Collect an array of pairs, which we can use to build the hash we want
    pairs = association_names.collect do |association_name|
      # Get the association object(s)
      object_or_array = me.send(association_name)
      # Build the single pair for this association
      if object_or_array.is_a? Array
        # If this is a has_many or the like, use the same array-of-pairs trick
        # to build a hash of "id => attributes"
        association_pairs = object_or_array.collect { |o| [o.id, o.attributes] }
        [association_name, Hash[*association_pairs.flatten(1)]]
      else
        # has_one, belongs_to, etc.
        [association_name, object_or_array.attributes]
      end
    end
    # Build the final hash
    Hash[*pairs.flatten(1)]
  end
end

А вот irb сеанс через скрипт / консоль , чтобы показать, как это работает. Во-первых, некоторая среда:

>> t = Target.create! :name => 'foobar'
=> #<Target id: 1, name: "foobar">
>> t.tags.create! :name => 'blueish'
=> #<Tag id: 1, name: "blueish", target_id: 1>
>> t.tags.create! :name => 'friendly'
=> #<Tag id: 2, name: "friendly", target_id: 1>
>> t.tags
=> [#<Tag id: 1, name: "blueish", target_id: 1>, #<Tag id: 2, name: "friendly", target_id: 1>]

А вот результат работы нового метода:

>> t.associations_attributes
=> {:tags=>{1=>{"id"=>1, "name"=>"blueish", "target_id"=>1}, 2=>{"id"=>2, "name"=>"friendly", "target_id"=>1}}}
16
ответ дан 5 December 2019 в 09:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: