使用delegate with has_many在Rails? [英] Using Delegate With has_many In Rails?
问题描述
我们有2个模特&连接模型:
#app / models / message.rb
类消息< ActiveRecord :: Base
has_many:image_messages
has_many:images,through::image_messages
end
#app / models / image.rb
Class Image < ActiveRecord :: Base
has_many:image_messages
has_many:messages,through::image_messages
end
#app / models / image_message.rb
Class ImageMessage < ActiveRecord :: Base
belongs_to:image
belongs_to:message
end
< hr>
额外属性
我们希望从连接模型中提取额外的属性( ImageMessage
),并在 Message
模型中访问它们:
@ message.image_messages.first.caption# - >现在发生什么
@ message.images.first.caption# - >我们需要
我们已经使用 select
方法时声明的关联:
#app / models / message.rb
has_many:images, > {select(#{Image.table_name}。*,#{ImageMessage.table_name} .caption AS caption)},class_name:'Image',through::image_messages,dependent::destroy
代表
我们刚刚发现 委托
方法,这正是这需要的。但是,它只适用于 has_one
和 belongs_to
关联
我们只是使用一个单一的协会,但似乎它不工作的集合(只需要你到一个公共方法)
问题
你知道我们可以返回 .caption $通过 Image
模型从 ImageMessage
连接模型中创建c $ c>属性?
我们目前有:
#app / models / image.rb
; ActiveRecord :: Base
has_many:image_messages
has_many:messages,through::image_messages
delegate:caption,to::image_messages,allow_nil:true
end
#app / models / image_message.rb
Class ImageMessage< ActiveRecord :: Base
belongs_to:image
belongs_to:message
def self.caption# - >只有类方法
#我们在这里放吗?
end
end
更新
感谢Billy Chan(对于实例方法的想法),我们已经非常
#app / models / image.rb
Class Image< ActiveRecord :: Base
#Caption
def caption
self.image_messages.to_a
end
end
#app / views / messages / show.html.erb
<%= @ message.images.each_with_index do | i,index | %>
<%= i.caption [index] [:caption]%> # - >工作,但超粗略
<%end%>
任何重构的方式,特别是让每次 .caption
被调用,它返回该记录的 image_message.caption
值?
解决方案 委托
只是等效实例方法的简写。这不是所有的解决方案,甚至有一些争论,它不是那么明确。
当简单委托
不能使用时,可以使用实例方法。
def image_message_caption
image_messages.class caption
end
任何关联都是不必要的。 ImageMessage的类方法caption更像一个常量,可以直接引用它。
def image_message_caption
ImageMessage.caption
end
We've got 2 models & a join model:
#app/models/message.rb
Class Message < ActiveRecord::Base
has_many :image_messages
has_many :images, through: :image_messages
end
#app/models/image.rb
Class Image < ActiveRecord::Base
has_many :image_messages
has_many :messages, through: :image_messages
end
#app/models/image_message.rb
Class ImageMessage < ActiveRecord::Base
belongs_to :image
belongs_to :message
end
Extra Attributes
We're looking to extract the extra attributes from the join model (ImageMessage
) and have them accessible in the Message
model:
@message.image_messages.first.caption # -> what happens now
@message.images.first.caption #-> we want
We've already achieved this using the select
method when declaring the association:
#app/models/message.rb
has_many :images, -> { select("#{Image.table_name}.*", "#{ImageMessage.table_name}.caption AS caption") }, class_name: 'Image', through: :image_messages, dependent: :destroy
Delegate
We've just found the delegate
method, which does exactly what this needs. However, it only seems to work for has_one
and belongs_to
associations
We just got this working with a single association, but it seems it does not work for collections (just takes you to a public method)
Question
Do you know any way we could return the .caption
attribute from the ImageMessage
join model through the Image
model?
We have this currently:
#app/models/image.rb
Class Message < ActiveRecord::Base
has_many :image_messages
has_many :messages, through: :image_messages
delegate :caption, to: :image_messages, allow_nil: true
end
#app/models/image_message.rb
Class ImageMessage < ActiveRecord::Base
belongs_to :image
belongs_to :message
def self.caption # -> only works with class method
#what do we put here?
end
end
Update
Thanks to Billy Chan (for the instance method idea), we have got it working very tentatively:
#app/models/image.rb
Class Image < ActiveRecord::Base
#Caption
def caption
self.image_messages.to_a
end
end
#app/views/messages/show.html.erb
<%= @message.images.each_with_index do |i, index| %>
<%= i.caption[index][:caption] %> #-> works, but super sketchy
<% end %>
Any way to refactor, specifically to get it so that each time .caption
is called, it returns the image_message.caption
value for that particular record?
解决方案 delegate
is just a shorthand as equivalent instance method. It's not a solution for all, and there are even some debate that it's not so explicit.
You can use an instance method when simple delegate
can't fit.
def image_message_caption
image_messages.class.caption
end
I reviewed and found any association is unnecessary is this case. The ImageMessage's class method caption is more like a constant, you can refer it directly.
def image_message_caption
ImageMessage.caption
end
这篇关于使用delegate with has_many在Rails?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!