3

Let's say you have two models: articles and comments.

class Article < ActiveRecord::Base
  has_many :comments
end

You know you can fetch associated comments to an article like this:

article = Article.first
article.comments # => SELECT * FROM "comments" WHERE ("comments".article_id = 123)

Is there a way to explicitly access the article_id (123) within a named_scope?

I need this for a complex named_scope that joins another table. Basically the named_scope will depend on to be called from the associated parent object to make sense (article.comments.my_named_scope and not Comments.my_named_scope).

I don't want to pass the id as a parameter for the named_scope. So, instead of passing the article_id to the named scope with ... lambda { |article| ...} and access the id with "... #{article.id} ...", I want to somehow access this article_id that the others method uses, which I get from the has_many association.

Daniel Pietzsch
  • 1,369
  • 14
  • 21

4 Answers4

4

Sounds like what you're actually after is an association extension: http://guides.rubyonrails.org/association_basics.html#association-extensions

In particular, proxy_owner, which will be the @article in question

eg:

class Article < ActiveRecord::Base
  has_many :posts do
    def sample_extension
      puts "Proxy Owner #{proxy_owner}"
    end
  end
end

@article.posts.sample_extension
Mark Connell
  • 3,739
  • 1
  • 16
  • 11
  • Originally, I wanted to access the parent's object id for use in a JOIN statement of my named_scope. This doesn't seem to be possible. But it **is** possible when I use an association extension and use the `proxy_owner` variable. So, this is not exactly how I would like to have it worked, but still good. Thanks for your answer, Mark. – Daniel Pietzsch Feb 08 '10 at 03:41
  • 1
    proxy_owner() is [deprecated](http://apidock.com/rails/ActiveRecord/Associations/CollectionProxy/proxy_owner) from Rails 3.1.0. In the newer version of Rails, the owner object can be simple accessed using `@association.owner` method inside the extension or using another alternative method. Code snippets are in my answer. – CodeExpress Jan 08 '16 at 01:11
2

Been struggling with the same issue. You can try this, which is a more elegant than using association extensions:

class Article < ActiveRecord::Base
  has_many :posts
end

class Post < ActiveRecord::Base
  def self.get_article_id
    self.new.article_id
  end
end

@article = Article.new
@article.posts.get_article_id

Within class methods for Post, you can now just use get_article_id anywhere you need the ID of the parent article. With proxy associations, I wasn't able to do that.

Adam Grant
  • 12,477
  • 10
  • 58
  • 65
Chanpory
  • 3,015
  • 6
  • 37
  • 49
0

I like @ajkochanowicz's solution but looks like there's a DB hit involved there (Rails 3.2.x), so just a heads up, not really ideal considering the fact that you already have the parent object on hand somewhere.

life_like_weeds
  • 131
  • 1
  • 4
0

For Rails 4 and above

The newer way to do it in Rails4+ is:

class Article < ActiveRecord::Base
  has_many :comments do
    def my_named_scope
      puts "Scope Owner = #{@association.owner}"
    end
  end
end

article = @article.comments.my_named_scope

Inside the scope my_named_scope, @association.owner returns the Article object that .comments was called on. Hence the article returned by the code above is same as the @article object.

Alternative method

If you don't want to use extensions and would rather avoid the "create a new object and get id from there" method (as described by Chanpory's answer), here is how to do it:

class Article < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  def self.get_article_id
    Comment.scope_attributes["article_id"] # scope_attributes returns a hash of all the attributes inherited from the owner of this scope
  end
end

@article = Article.find(10)
@article.comments.get_article_id  # returns 10
Community
  • 1
  • 1
CodeExpress
  • 2,202
  • 1
  • 20
  • 16