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.
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
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With