从HMT连接表获取属性的最有效方法是什么?

时间:2015-12-17 01:54:24

标签: ruby-on-rails join activerecord associations has-many-through

现在,我有一个Artist模型设置作为自我联接,在这种情况下艺术家可以属于group和一组members(即艺术家)。我还有一个建立这些成员资格的联接表。在联接表中,有一个枚举属性status,用于确定艺术家是否为活跃会员。

在rails控制台中进行实验时,我设法检索艺术家的会员身份,执行以下操作:

Artist.first.memberships.find_by(group: 3).status
=> "active"

我想将此作为艺术家的实例方法引入我的项目,但感觉这个查找链可以改进。

class Artist < ActiveRecord::Base
  has_many :group_memberships, class_name: "Membership", foreign_key: :group_id
  has_many :members, through: :group_memberships

  has_many :memberships, foreign_key: :artist_id
  has_many :groups, through: :memberships
end

class Membership < ActiveRecord::Base
  enum status: [:active, :inactive]

  belongs_to :member, class_name: "Artist", foreign_key: :artist_id
  belongs_to :group, class_name: "Artist"
end

我在考虑通过每个小组成员列举并显示他们的状态:

<% @artist.members.each do |member| %>
  <%= member.group_status(@artist) %>
<% end %>

这就是实例方法的编写方式:

def group_status(group)
  memberships.find_by(group: group).status
end

这样做有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

您需要ActiveRecord Association Extensions

#app/models/artist.rb
class Artist < ActiveRecord::Base
  has_many :memberships do
      def status_by_group group
         select(:status).find_by(group_id: group)
      end
  end
  has_many :groups, through: :memberships
end

通过这种方式,您将能够:

@artist = Artist.find params[:id]
@artist.memberships.status_by_group(2) #-> should return object with status of Membership

有更好的方法。

如果您想将status属性附加到group个对象:

@artist.groups.find(1).status

...您可以使用ActiveRecord关联扩展功能,但这次使用proxy_association个对象。

之前我已经完成并创建了以下代码:

#app/models/artist.rb
has_many :memberships
has_many :groups, through: :memberships, extend: GroupStatus

#app/models/concerns/group_status.rb
module GroupStatus

      #Load
      def load
        statuses.each do |status|
            proxy_association.target << status
        end
      end

      private

      #Status
      def statuses
        return_array = []
        through_collection.each_with_index do |through,i|
            associate = through.send(reflection_name)
            associate.assign_attributes({status: items[i]})
            return_array.concat Array.new(1).fill( associate )
        end
        return_array
     end

     #######################
     #      Variables      #
     #######################

     #Association
     def reflection_name
        proxy_association.source_reflection.name
     end

     #Foreign Key
     def through_source_key
        proxy_association.reflection.source_reflection.foreign_key
     end

     #Primary Key
     def through_primary_key
        proxy_association.reflection.through_reflection.active_record_primary_key
     end

     #Through Name
     def through_name
        proxy_association.reflection.through_reflection.name
     end

     #Through
     def through_collection
        proxy_association.owner.send through_name
     end

     #Statuses
     def items
        through_collection.map(&:status)
     end

     #Target
     def target_collection
        proxy_association.target
     end

end