Im trying to display recently added comments from tattoos a user has posted. So If I posted a tattoo, and then user_b posted "hey I like your tattoo" then Im trying to get just the comment.
First of all Im using the acts_as_commentable_with_threading gem which doesnt create a foreign key for the table im trying to join. So my controller cant look for tattoo_id, it has to look for commentable_id
In the controller I would have to call the Comment model and then pass some SQL stuff into it but apparently I have no clue how to pass custom SQL queries into ruby because even tho my query string works in terminal, I get all sorts of nonsense when trying to use it in rails.
Im basically trying to do this:
SELECT comments.id FROM comments,tattoos WHERE commentable_id = tattoos.id AND
tattoos.member_id = #{current_user}
where #{current_user} will be the current_user passed in.
You don't have to jump through so many hoops to accomplish this. acts_as_commentable assigns a polymorphic association, so you should set it up like this:
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :commentable, :polymorphic => true
end
class Tattoo < ActiveRecord::Base
has_many :comments, :as => :commentable
end
class User
has_many comments
end
Then you can access the association as usual:
Tattoo.where(:member_id => current_user).first.comments
See http://railscasts.com/episodes/154-polymorphic-association for a general tutorial on how polymorphic associations work. It just so happens that this railscast uses exactly :commentable as the polymorphic example, so you should be able to follow along directly if you want.
I think Ben's approach is best but for future reference if you do come across something more complicated you can always use sql for example:
Comment.find_by_sql("SELECT comments.* FROM comments,tattoos WHERE commentable_id = tattoos.id AND tattoos.member_id = ?", current_user)
Related
I've not been able to figure this one out -- perhaps I've missed something in the docs. I want to get all of the articles that are associated with published issues. (That is, article.issue.is_published = true.)
I have two models:
# Article model
class Article < ActiveRecord::Base
belongs_to :issue
...
end
# Issue model
class Issue < ActiveRecord::Base
has_many :articles
...
end
From what I understand, I can run something like this:
Article.includes(:issues)
.where('issue.is_published = true')
.references(:issues)
But I get nothing but funky business on the other end. All of the examples I've found have one-to-many relationships going the other way - I assumed that I've gotten something wrong with the naming convention, but no combination of "issue" and "issues" seems to work any better.
What am I missing here?
You'll want to do a joins instead of includes here. This translates to a SQL inner join. Article.joins(:issue).where(issues: {is_published: true})
I'm learning Rails and I'm trying to connect the dots between Ruby and what's going on when creating associations. For example:
class Post < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :posts
end
I've read an explanation online that relates the use of belongs_to and has_many here to attr_accessor in Ruby. This is a tad confusing ... how is that so? I understand this sets up the 1:M association between Post and User, specifically Post has a foreign key containing a user id. In the rails console, I can do something like:
user = User.first
user.posts
user2 = User.create(username: 'some guy').save
post2 = Post.new(title: 'stuff', body: 'some more stuff')
user2.posts << post2
So are these kind of like 'getter' and 'setter' methods where an object of each class corresponds to a specific row in the database and I can use these methods because of their association/relationship?
To answer your exact question, the answer is "kinda yes, kinda no".
What rails does internally to set up the association is pretty complicated. yes, getter/setter methods are involved, yes, pointing at table rows are involved... but this isn't exactly what Active Record does, and it isn't only what Active Record does.
If you really want to know what Active Record does inside: you can just go and look at the source code on github.
If you have a more specific question... I recommend you update your question to ask that :)
I have a polymorphic model that can relate to itself:
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
has_many :comments, as: :commentable
end
These relationships work perfectly, except when I'm trying to call the full tree of child/parent comments through an include statement:
Post.find(1).include(:comments)
This only includes the comments directly tied to the post. I could perhaps retrieve a second level with:
Post.find(1).include(comments: :comments)
But what if I wanted to get all comments descending from the post, no matter how deeply nested? Is this possible?
It seems that you want to retrieve an adjacency list. Rails has no immediate support for it, but if you are using postgresql, you can use the "WITH RECURSIVE" operator.
That plugin takes care of it : https://github.com/chrisroberts/acts_as_sane_tree
Otherwise, you can pretty easily create your own postgresql function (declare it in a migration), and then use it in your queries. Have a look at : http://wiki.postgresql.org/wiki/Getting_list_of_all_children_from_adjacency_tree
WITH RECURSIVE is not currently implemented in mysql or sqlite3.
I'm working on a small blog engine.
There are the following tables: Blog and Message.
Blog has a foreign key: last_message_id, so I access the last message in the blog by calling blog.last_message
I have the following code to make it work:
class Blog < ActiveRecord::Base
belongs_to :last_message, :class_name => "Message"
end
I need to order the blogs by the last messages. But when I call
blogs.order("last_message.created_at DESC")
It doesn't work. I get the following error:
PGError: ERROR: missing FROM-clause entry for table "last_message"
ORDER BY last_messa...
How can I make it work?
UPDATE
Here's the solution:
blogs.joins(:last_message).order("messages.created_at DESC").
I think your model is wrong. See rails automaticly add 2 attributes to a model : created_at and update_at. So having a relationship like you describe is redondant. To me, it should look like this :
#model/blog.rb
class Blog < ActiveRecord::Base
has_many :messages
end
#model/message.rb
class Message < ActiveRecord::Base
belongs_to :blog
end
Then, to get the blogs ordered by the last message, you could do this :
Blog.joins(:messages).order("messages.created_at_desc")
That as you may have noticed will give you double entries for your blog model. If that is not a problem, go ahead. If it is, you have two options : doing a each and test if you already saw the blog - if not, you display it. Or, you could write your own sql.
You have to make sure the last-messages are also selected to make that order-command work.\
So something like:
blogs.includes(:last_message).order("last_message.created_at desc")
I have a polymorphic association like this -
class Image < ActiveRecord::Base
has_one :approval, :as => :approvable
end
class Page < ActiveRecord::Base
has_one :approval, :as => :approvable
end
class Site < ActiveRecord::Base
has_one :approval, :as => :approvable
end
class Approval < ActiveRecord::Base
belongs_to :approvable, :polymorphic => true
end
I need to find approvals where approval.apporvable.deleted = false
I have tried something like this -
#approvals = Approval.find(:all,
:include => [:approvable],
:conditions => [":approvable.deleted = ?", false ])
This gives "Can not eagerly load the polymorphic association :approvable" error
How can the condition be given correctly so that I get a result set with approvals who's approvable item is not deleted ?
Thanks for any help in advance
This is not possible, since all "approvables" reside in different tables. Instead you will have to fetch all approvals, and then use the normal array methods.
#approvals = Approval.all.select { |approval| !approval.approvable.deleted? }
What your asking, in terms of SQL, is projecting data from different tables for different rows in the resultset. It is not possible to my knowledge.
So you'll have to be content with:
#approvals = Approval.all.reject{|a| a.approvable.deleted? }
# I assume you have a deleted? method in all the approvables
I would recommend either of the answers already presented here (they are the same thing) but I would also recommend putting that deleted flag into the Approval model if you really care to do it all in a single query.
With a polymorphic relationship rails can use eager fetching on the polys, but you can't join to them because yet again, the relationships are not known so the query is actually multiple queried intersected.
So in the end if you REALLY need to, drop into sql and intersect all the possible joins you can do to all the types of approvables in a single query, but you will have to do lots of joining manually. (manually meaning not using rails' built-in mechanisms...)
thanks for your answers
I was pretty sure that this couldn't be done. I wanted some more confirmation
besides that I was hoping for some other soln than looping thru the result set
to avoid performance related issues later
Although for the time being both reject/select are fine but in the long run I
will have to do those sql joins manually.
Thanks again for your help!!
M