Is an object in a given collection? - ruby-on-rails

Let's say I have a blog application. On each Post there are Comments.
So, I have a collection of comments in "Post.comments"
Let's say I have an object called "this_comment"
Is there a magical keyword or construct in Ruby such that I can test "is 'this_comment' in 'Post.comments"?
In other words, I want to know if "this_comment" is a member of the collection "Post.comments". I could do a 'find' and get my answer, but it seems like the kind of thing that Ruby might make easy via a cool keyword like "if this_comment.in(Post.comments)"
I suppose if not, I could just write my own "in" method for "Comment" (or 'is_in' method, as I think 'in' is a reserved keyword).
Thanks!

As an array you can do
[:a, :b, :c].include?(:a)
But ActiveRecord does some cool things to keep your queries sane if you are dealing with models. Assuming comments is a named scope or association of some sort you can do:
Post.comments.exists?(this_comment.id)
named scopes and associations can have pretty much all of the Activerecord class methods called on it

How did you define the relationship between 'Post' and 'Comments'? Post has_many Comments ?
If so, try .exists?().

Related

Rails associations. How do they work?

What is the exact purpose of associations? I understand what the relationships mean and when to use each type for example:
belongs_to, has_many, has_one , has_and_belongs_to_many, ect
but i dont quite understand what purpose they serve in terms of how the connect things within rails. Any input would be appreciated. Thanks!
What you're calling "associations" I would call "macros". That is, the belongs_to, has_many etc. macros are simply class methods being called on your ActiveRecord objects which, when called, define a bunch of functionality based on the association name.
So, what you're asking is: What functionality do these macro methods define? The answer for that lies within the Rails documentation for each of these methods:
has_many
belongs_to
has_one
And, even more, you should read the overall documentation on ActiveRecord::Associations::ClassMethods.
But, in short, these macros define methods with names based on the association names you pass into them. So, for example:
belongs_to :my_object
Will define, as a greatly-simplified example:
def my_object
MyObject.find_by_id(my_object_id)
end
So it's basically like metaprogramming your objects to have the methods needed to find the other, associated objects, update their collections, and so on.

Rails: Get all associated models from has-many association

I need to get all associated models from the other associated model, on which I want to run query first.
For example, I got Post model and Tag model. I need to get all Posts, which associated with some Tags.
There's no problem, if I have only one Tag – just call 'tag.posts', but if I have more, then one Tag – for example, I need to do somethink like:
Post.where(id: PostTag.where(tag_id: some_ids).pluck(:category_id).uniq)
I belive that Rails have a built-in solution. So, anybody knows it?
My thought is:
Post.joins(:post_tags).where('post_tags.tag_id' => some_ids).uniq
You can make it a scope for easier reuse. I don't think there is a built-in method for this situation.

How do I make a query in Ruby on Rails to filter if an object's object's object is nil

I am using Rails 2.3.10. I have models called Stream, Buzz, and BuzzDigest. There is an association, buzz has_many :streams. There is another association, buzz has_one :digest. Sometimes, buzz.digest is nil. How do I write a query for Stream that would filter out streams where the stream's buzz's digest is nil?
This isn't correct syntax, but might be close to what I want:
Stream.find( :all, :conditions => "buzz_id.digest IS NOT NULL" )
Since BuzzDigest is an Object, and not a DB field or attr_accessor, you may want to fix the fact that buzz.digest CAN be nil in the first place within the design of your app.
If you balk at that, quick thought has something like:
Stream.includes[:buzzes, :buzz_digests].group(:id)
assuming the right schema. SO question may have some hints too.

How to access aliased attributes in ActiveRecord class? Is there a better way I'm missing?

I'm interfacing with an older database and have mapped the old column names to the new ones using alias_attribute.
It works great, but I also want to get a list of all the attributes for a record too. Using record.attributes only gives me the original attributes, not the aliased ones too. Is there a way I can list all these through a similar method?
Maybe I would be better off just making a lookup hash?
Thanks in advance!
I'm afraid it isn't possible to get the list of aliased attributes. The alias_attribute method does nothing beyond creating few getters/setters. This method doesn't "mark" these methods in any way.

How do nested resources work?

As the official site, I defined two models Post and Comment. Comment is nested in Post.
resources :posts do
resources :comments
end
So I can use #post.comments to access all comments a post own. In console:
$ post = Post.new()
$ post.comments.class
> Array
But:
$ post.comments.respond_to?("build")
> true
Why? An array has the method build? How did Rails do? And how can I know other hidden methods of post.comments?
Firstly, your resources calls are in your routes.rb file, which only deals with the URL parsing side of Rails. It's nothing to do with the associations between your models, which are set up using has_many and belongs_to calls in the relevant model files. Ignore the routes file for now as it's not related to the main part of your question.
With respect to associations, you'll find that post.comments is not returning you an Array, it's actually returning an ActiveRecord::Relation object. A Relation object is like an array - in fact any method you call on it which isn't relation-specific (like build) is actually passed on to an Array representation of the Relation's contents. So, when you call post.comments.length, the comments association object is calling .length on its internal array.
One of the consequences of this is that calling post.comments.class actually passes on the .class call to the Array too!
So, what can that Relation object actually do? Since the association is set up by the has_many call, you can find out in the has_many documentation. Similarly for a belongs_to association
In ruby you can add or change any method in any object. You can even add a new method to a string instance, for example:
x = "xyzzy"
x.name # => NoMethodError: undefined method `name' for "xyzzy":String
x.instance_eval do
class << self
define_method(:name) {"I got a name"}
end
end
x.class # => String
x.name # => "I got a name"
y = "other"
y.class # => String
y.name # => NoMethodError: undefined method `name' for "other":String
That build method might have been 'added' to an instance of Array returned by the comments accessor, created by a has_many macro. (As Gareth pointed, Rails complicated things a little, and the associations do not work this way. However, extending the objects may be a more 'clean' way in comparison to working as transparent proxy. Consider my example as a ruby-related, not rails)
As for the second part of your question, you may know the methods of a given object by accessing its methods function. It returns the names of all the (public) methods defined for this object. (If you want private ones, see the private_methods function.)
In my example x.methods would include also the newly defined "name" method, but y.methods will not.
There are also other functions in ruby, with which you can examine the objects. You may find them in Ruby API documentation. The API may have some (usually slight) changes in various versions of ruby. See the documentation for the version you are using.
If you want to examine the code of some method, then it may be a little problem, because the "executable code" of a function may be created by many ways: it may be a copy (alias) of another function, it may be created dynamically by using eval function, and so on.
Knowing the name of the method you may 'grep' the source code you have available, and maybe the method you want has not been created dynamically.
I see that the project ParseTree is still alive. Maybe you will find it helpful, if you really want to know the code of a function to which you do not have sources.

Resources