Rails 3 ActiveRecord Query questions - ruby-on-rails-3

I've implemented "following" function. Showing "people user A is following" was simple, but showing "people who are following user A" is giving me troubles.
I have follow_links, which have id, user_id, and follow_you_id column. When user A begins following user B, the columns will be like (user_id = A, follow_you_id = B).
To show users that A(#user) is following, I can simply do
#follow_yous = #user.follow_yous
But I'm not sure how to show users who are following A(#user)
To do this, I first found all the related links.
#follow_links = FollowLink.where(:follow_you_id => #user.id)
Now I thought I could just do #follow_mes = #follow_links.users, but it says user is an undefined method. So I guess I can either call user.follow_yous or follow_you.users.
My next approach was
#follow_links = FollowLink.where(:follow_you_id => #user.id)
#follow_mes = User.where(:id => #user.id, :include => #follow_links)
I intended to find all the User objects that had the provided #follow_links objects, but I think the syntax was wrong. I couldn't find a decent solution after a bit of research. I'd appreciate any help.
Update:
FollowLink model
belongs_to :user
belongs_to :follow_you, :class_name => "User"

You can use joins like this:
#users = User.joins(:follow_links).where(:follow_links => { :follow_you_id => #user.id })

you can use following:
#follow_links = FollowLink.where(:follow_you_id => #user.id)
#follow_links.collect(&:user) # :user should be the name of your relation to user in your followlink model
=> [User1, User2,...]

Related

rails - find with condition in rails 4

I recently upgraded my rails to Rails 4.1.6.
This query used to work :
#user = User.find(:all, :conditions => { :name => 'batman' })
Now I get this error message:
Couldn't find all Users with 'id': (all, {:conditions=>{:name=>"batman"}}) (found 0 results, but was looking for 2)
When I check the logs I can see that rails is trying to do a completely different query :
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" IN ('all', '---
:conditions:
:name: batman
')
It looks like, it's trying to get all the users with the id "all" and "{:conditions=>{:name=>"batman"}}". Please help.
UPDATE:
My real question behind that was I want to get a specific user and add to it his cars, only the cars that are blue. For example this is my query, the user id is 20.
#user = User.joins(:cars).find(20, :cars => {:color => "blue"})
But I get this error:
Couldn't find all Users with 'id': (20, {:cars=>{:color=>"blue"}})
(found 41 results, but was looking for 2)
You should definitely read this ActiveRecord Query Interface quide
User.where(name: "batman")
Some others already pointed out: The query syntax changed. Try this:
#user = User.joins(:cars).where(:cars => { :color => "blue" }).find(20)
Note that this will raise an exception if that record is not found, to return an array empty instead call:
#user = User.joins(:cars).where(:id => 20, :cars => { :color => "blue" })
I suggest to read: http://guides.rubyonrails.org/active_record_querying.html
If you want to load the user even if he does not have any cars and than display only his blue cars, I would do it like this:
#user = User.find(20) # returns the user
#user.cars.where(:color => 'blue') # returns the user's blue cars (or an empty array)
The find method is deprecated in this version of Rails (see the reference).
Instead, you must use the where method.
In your case, you should write #user = User(:name => 'batman') or #user = User(name: 'batman')

Rails 3: Polymorphic conditioned query

I've got the following models:
class Notification < ActiveRecord::Base
belongs_to :notificatable, polymorphic: true
end
class BounceEmailNotification < ActiveRecord::Bas
has_one :notification, :as => :notificatable, :dependent => :destroy
end
class UserNotifierEmailNotification < ActiveRecord::Base
has_one :notification, :as => :notificatable, :dependent => :destroy
end
As you can see, a notification can be of type "bounce email notification" or "user notifier email notification". The BounceEmailNotification model has a event string attribute. What if I want retrieve all user notifier email notifications and all bounce email notifications which have a specific event value, ordered by created_at?
Something like this (using squeel):
(Notification.joins{ notificatable(BounceEmailNotification) }.where('bounce_email_notifications.event' => 'error') + Notification.joins { notificatable(UserNotifierEmailNotification) }).sort_by { |n| n.created_at }
will work, but I don't want to use Ruby to order the notifications. What can I do? Thanks
Try this.
Notification.joins('left outer join bounce_email_notifications on notifications.notificatable_id = bounce_email_notifications.id and notificatable_type = "BounceEmailNotification"').
where("bounce_email_notifications.event = ? or notificatable_type = ?",'error',UserNotifierEmailNotification.to_s).
order('notifications.created_at')
This is using active record 3.2 but I guess it should work in rails 3.
I have not used squeel cant comment much on how to use it with squeel but this can give you a brief idea.
In squeel I came up with something like this ( NOT TESTED) created by using squeel docs
Notification.notificatable{notable(BounceEmailNotification).outer}. where{
{ ('bounce_email_notifications.event'=>'error') | (:notificatable_type=>UserNotifierEmailNotification.to_s) }
Conceptual steps
left join on the bounce_email_notifications to get all bounce_email_notifications and and non bounce_email_notifications notification in result
check if the bounce_email_notifications.event = event
or
notificatable_type = 'UserNotifierEmailNotification' for all UserNotifierEmailNotification records
sort the records by notifications.created at
Hope this helps.

Active Record Querying belong_to

I have the two following models associated:
class Post < ActiveRecord::Base
belongs_to :language
end
class Language < ActiveRecord::Base
has_many :posts
end
From a view I have a link to filter the posts by language:
<div id="english"><%= link_to "English", {:controller => 'posts', :action => 'search_result', :language => "english"} %></div>
The model language has a variable name:string which is the one i am using to make the active record query.
The doubt i have is how i can make this query from the post controller to retrieve the right posts which has a field: language.name == "english".
I tried this:
#posts = Post.all(:conditions => ["language.name = ?", params[:language]])
and also this:
#posts = Post.where(:language.name => params[:language])
Hope i have explained well the issue, i am a quite newbie yet. Ah! i would also know what would it be better in this case to use: "all" or "where" ??.
Thanks a lot in advance.
You need to do a join: http://guides.rubyonrails.org/active_record_querying.html#specifying-conditions-on-the-joined-tables
If I have understood your models/database structure correctly, the ActiveRecord call should looks something like:
Post.joins(:language).where('languages.name' => params[:language])
Hope that helps.
PS. The where call is the preferred method these days.

Will_Paginate and order clause not working

I'm calling a pretty simple function, and can't seem to figure out whats going on. (I'm using rails 3.0.3 and the master branch of 'will_paginate' gem). I have the following code:
results = Article.search(params) # returns an array of articles
#search_results = results.paginate :page => params[:page], :per_page=>8, :order => order_clause
No matter what I make the order_clause (for example 'article_title desc' and 'article_title asc'), the results are always the same in the same order. So when I check using something like #search_results[0], the element is always the same. In my view, they are obviously always the same as well. Am I totally missing something?
I'm sure its something silly, but I've been banging my head against the wall all night. Any help would be much appreciated!
Edited to Add: The search clause does the following:
def self.search(params)
full_text_search(params[:query].to_s).
category_search(params[:article_category].blank? ? '' : params[:article_category][:name]).
payout_search(params[:payout_direction], params[:payout_value]).
length_search(params[:length_direction], params[:length_value]).
pending.
distinct.
all
end
where each of these guys is a searchlogic based function like this:
#scopes
scope :text_search, lambda {|query|
{
:joins => "INNER JOIN users ON users.id IN (articles.writer_id, articles.buyer_id)",
:conditions => ["(articles.article_title LIKE :query) OR
(articles.description LIKE :query) OR
(users.first_name LIKE :query) OR
(users.last_name LIKE :query)", { :query => "%#{query}%" }]
}
}
scope :distinct, :select => "distinct articles.*"
#methods
def self.payout_search(dir, val)
return no_op if val.blank?
send("payment_amount_#{dir.gsub(/\s+/,'').underscore}", val)
end
def self.length_search(dir, val)
return no_op if val.blank?
send("min_words_#{dir.gsub(/\s+/,'').underscore}", val)
end
Thanks.
If you look at the example from the will_paginate github page you can spot one important difference between their use of the :order clause and yours:
#posts = Post.paginate :page => params[:page], :order => 'created_at DESC'
This calls paginate on the Post object (with no objects being selected yet - no SQL has been executed before paginate comes along). This is different in your example: as you state in the first line of code "returns an array of articles". The simplest I can come up with showing the problem is
results = Model.limit(5).all
#results = results.paginate :order => :doesnt_matter_anymore
won't sort, but this will:
results = Model.limit(5)
#results = results.paginate :order => :matters
It should suffice to take the all out of the search method. It makes ActiveRecord actually perform the SQL query when calling this method. Will_paginate will do that for you when you call paginate (if you let it...). Check out the section on Lazy Loading in this post about Active Record Query Interface 3.0

Correct this Rails/ruby method for me, please?

I've a post model with act-as-taggable-on gem. Both tables have timestamps.
I started with
def tags
#posts = current_user.posts.find_tagged_with(params[:tag], :order => "#posts.tags.updated_at DESC"])
end
And when that didn't work, I tried changing things and ended up with this mess.
def tags
#posts = current_user.posts.find_tagged_with(params[:tag])
#tags = #posts.tags.all
#posts = #tags(params[:tag, :order => "#posts.tags.updated_at DESC"])
end
I basically want to sort by when the tags was last updated.
Bonus: Sort by tag.updated_at or post.updated_at, but in this particular app, I'll be updating tags the most, so just first one will be fine.
Any help is appreciated.
You have to join the tags table in your find statement:
def tags
#posts = Post.find_tagged_with(
params[:tag],
:conditions => {:user_id => current_user.id},
:joins => :tags,
:order => 'tags.updated_at DESC',
:group => 'posts.id'
)
end
Note: Find the right conditions to select only posts from the current user. This example could work, though.