Search code examples
ruby-on-railsrails-activerecordhas-many-throughmodel-associationsrails-postgresql

Creating a feed => NoMethodError: undefined method for ActiveRecord_Associations_CollectionProxy


I am implementing a feed of all cards belonging to the tags a user has subscribed to and I get the following error. It's probably something trivial but I can't pinpoint what needs work.

NoMethodError: undefined method `cards' Tag::ActiveRecord_Associations_CollectionProxy:0x007fbaa46239f8>

Here are my models:

class User < ActiveRecord::Base
  has_many :cards, dependent: :destroy
  has_many :tags, through: :cards

  has_many :subscriptions, dependent: :destroy 
  has_many :subscribed_tags, through: :subscriptions, source: :tag
end
class Tag < ActiveRecord::Base
  has_many :taggings, dependent: :destroy
  has_many :cards, through: :taggings
  has_many :subscriptions, dependent: :destroy
  has_many :subscribers, through: :subscriptions, source: :user
end
class Card < ActiveRecord::Base
  acts_as_votable
  belongs_to :user
  has_many :taggings, dependent: :destroy
  has_many :tags, through: :taggings    
  def self.tagged_with(name)
    Tag.find_by_name!(name).cards
  end
  def self.tag_counts
    Tag.select("tags.*, count(taggings.tag_id) as count").
    joins(:taggings).group("taggings.tag_id")
  end
  def tag_list
     tags.map(&:name).join(", ")
  end
  def tag_list=(names)
    self.tags = names.split(",").map do |n|
       Tag.where(name: n.strip).first_or_create!
    end
  end
end

What I am really trying to do is to run current_user.subscribed_tags.cards and retrieve an array of cards I can reorder and output as a timeline.

Thanks


Solution

  • subscribed_tags - it's a scope (where(user: self)), you can call where or join on them but not an item methods.

    In your case you want to use a scope

    class Card
      scope :with_subscription, -> { joins(tags: :subscriptions) }
    end
    
    # In controller
    current_user.cards.with_subscription.order('cards.created_at DESC')
    

    You can imagine current_user.cards like another form of Cards.where(user: current_user). Once you tell that you will retrieve Card array - it cannot be changed. You cannot do user.cards.subscriptions or User.where(id: user).cards.tags the only you can do it's filter.

    Next we filter with joins(:subscriptions). It will give us inner join, so we get cards belonged to user that have subscriptions. And it's a scope we can modify further passing for example an order.

    activerecord join associations