Rails How to use join in this specific situation? - ruby-on-rails

I have three models, each connected as such: Groups which has many Students which has many Absences.
Absences has a field called created_on.
I only have a group id and would like to obtain all students with an absence of today.
I have created this method inside my Student model:
# Inside student.rb
def self.absent_today_in_group (group)
#SQLITE
find(:all, :joins => :absences, :conditions => ["STRFTIME('%d', created_on) = ? AND STRFTIME('%m', created_on) = ?", Date.today.day, Date.today.month])
#POSTGRES
#find(:all, :joins => :absences, :conditions => ["EXTRACT(DAY FROM created_on) = ? AND EXTRACT(MONTH FROM created_on) = ?", Date.today.day, Date.today.month])
end
Why would that query not return anything? And how could I then also check for group_id?

What version of rails are you using? You can do this in rails 3:
def self.absent_today_in_group(group)
joins(:absences, :group).where(
'absences.created_on' => (Time.now.beginning_of_day..Time.now.end_of_day),
'groups.id' => group.id
)
end
That would find all users which were absent for today for given group.

Shouldnt this be :where and not :conditions?

Related

Find result from joining a table in rails :conditions part

Currently the attachments are searched based on attachment_file_name, tags and employee_id, I would like to search based on Employee name as well, how can I go with it?
Two models must be used.
Employee - which has name of employee
LessonplanAttachment - contains the id of the employee.
The code part.
def search_ajax
#attachments = LessonplanAttachment.find(:all,
:conditions => ["attachment_file_name LIKE ? OR tags LIKE ? OR employee_id = ?",
"#{params[:query]}%","#{params[:query]}%",params[:query]])
end
try this
LessonplanAttachment.joins("JOIN employee on employee_id").find(:all, :conditions =>
["attachment_file_name LIKE ? OR tags LIKE ? OR employee_id = ? OR employee.name = ?",
"#{params[:query]}%","#{params[:query]}%",params[:query], params[:query]]
I guess you have the following association in your LessonplanAttachment model.
belongs_to :employee
Now you can change your code as per the following
#attachments = LessonplanAttachment.joins([:employee]).where("attachment_file_name LIKE ? OR tags LIKE ? OR employee_id = ? OR employees.name LIKE ?", "#{params[:query]}%","#{params[:query]}%",params[:query],"#{params[:query]}%")
Provided you have an association belongs_to :employee on your LessonplanAttachment class, for rails 2, you can add a :joins attribute to the options on find. Something like this should work:
#attachments = LessonplanAttachment.find(:all,
:joins => :employee,
:conditions => [
"attachment_file_name LIKE ? OR tags LIKE ? OR
employee_id = ? OR employees.name LIKE ?",
"#{params[:query]}%","#{params[:query]}%",params[:query],"#{params[:query]}%"])

How to query across a nested resource with a condition

I have the following models:
User (id)
UserRoom (user_id, room_id, banned(boolean)
Room (id, uuid)
Right now I can get all of a user's rooms as follows:
current_user.rooms.find_all_by_uuid(#requested_ids)
What I would like to do is expand this to only show rooms that aren't banned (banned => false).
What's the right rails way to add that condition to the query?
Thanks
Try using conditions like so:
current_user.rooms.find :all, :conditions => { :uuid => #requested_id, :banned => false }
Using #requested_ids as an array (probably not as elegant):
current_user.rooms.find :all, :conditions => ["uuid IN (?) AND banned=0", #requested_ids]

Adding another condition to existing named_scope

I am working on a Rails 2.3.9 app and my question involves both a self referencial relationship and a named_scope. This application allows users to log and share workouts. A workout can be public or private and that is designated by #workout.public == 1.
I allow users to 'follow' people. So on a current_user's dashboard I display all public workouts from users that current_user follows with the following code:
/dashboard/index.html.erb
<% current_user.friends_workouts.each do |workout| %>
<%= link_to (workout.title), workout %> <br/>
by <%= link_to (workout.user.username), workout.user %> - <%= time_ago_in_words(workout.created_at)%> ago</p>
<% end %>
user.rb
def friends_workouts
#friends_workouts ||= Workout.current.public_workouts.find_all_by_user_id(self.friends.map(&:id), :order => "created_at DESC", :limit => 3)
end
workout.rb
named_scope :public_workouts, :conditions => {:public => 1 }, :order => "created_at DESC"
I now want to add a condition to this scope as I am adding another level of sharing. Users can associate to a "box" (a gym really) through a "membership" model. So if the current_user belongs_to the same "box" as a user they follow, they should not only see the workouts marked public but also workouts where #workout.box_only == 1.
How can I affect the above to include all public workouts from followed users AND workouts from followed users where #workout.box_only == 1 and #workout.user.membership.box_id == current_user.membership.box_id. I know that syntax is incorrect but you get my point (hopefully).
UPDATE:
It also needs to be considered that :public_workouts is being called from pages that don't require a logged_in? user so in that case if the scope is trying to reference current_user it will throw an error.
UPDATE 2:
:user has_many :memberships
I believe something like the following should do it for you:
named_scope :public_workouts,
:joins => ", user, membership"
:conditions =>
"workouts.public = 1 or
membership.box_id = #{current_user.membership.box_id}",
:group => "workouts.id",
:order => "workouts.created_at DESC"
You would have to play around with this for a bit. The hard part every time I try something like this is to get the OR conditions correct. You want to get all public and those where the joined membership.box_id matches regardless of public being 1.
Edit: Admittedly this is perhaps not the most ruby way of building a query and I haven't tested it properly but something like below could also be made to work.
def self.public_workouts
query = Workout.joins(:user => { :membership })
if current_user
query.where('memberships.box_id = ? or workouts.public = 1', current_user.membership.box_id) unless current_user.membership.box_id.nil?
else
query.where('workouts.public = 1')
end
query.group('workouts.id')
query.order("workouts.created_at DESC")
return query
end
Edit2
Another alternative could be to create two separate scopes and create a class method that combines the two scopes. This class method would then be used in the view.
named_scope :box_workouts,
:joins => ", user, membership"
:conditions => "memberships.box_id = #{current_user.membership.box_id}"
:group => "workouts.id",
:order => "workouts.created_at DESC",
:select "workouts"
named_scope :public_workouts,
:conditions => :public => 1
:order => "workouts.created_at DESC"
def self.public_box_workouts
return box_workouts.merge(public_workouts).limit(3) if current_user
return public_workouts.limit(3)
end
Edit3 Not so hard, I believe something like below will work.
def self.box_and_public_workouts(user)
return public_workouts if user.nil? or user.memberships.blank?
return public_workouts + box_workouts(user.memberships.map(&:box_id))
end
named_scope :box_workouts, lambda { |box_ids| { :conditions => ['box_id IN (?)', box_ids], :order => 'created_at DESC' } }
Apologies for taking so long. I was missing confused with how the "old" way of querying the database. I went right for Rails3 :)
Anyway, I didn't want to commit anything so I tried to fork it to send a pull request but github is being rude to me tonight. Might just copy from here then.

trouble with some data management code in my sessions_controller

a user may belong to several groups.
a user may do a review of each group.
users have been deleted from groups without deleting reviews. this causes errors.
when a user logs in i want to delete user reviews for groups to which they no longer belong.
here is the code which isn't working:
#user = session[:user]
#group = session[:group]
#urevs = UserReview.find(:all, :conditions => ["user_id = ?", #user.id])
unless #urevs.nil?
#urevs.each do |r|
ur = #urevs.id
#rv = Review.find(:first, :conditions => ["id = ?", #urevs.review_id])
#gm = GroupMember.find(:first, :conditions => ["group_id = ? and user_id = ?", #rv.group_id, #user.id])
if #gm.nil?
#dest = UserReview.find(:first, :conditions => ["id = ?", ur])
#dest.destroy
end
end
end
I would prefer not to do a mysql query to remove all such instances.
Thanks.
#user.user_reviews.destroy_all(["user_reviews.group_id NOT IN (?)", GroupMember.where(:user_id => #user.id).all.map(&:group_id)])
This part can be replaced by a more convenient method #user.groups.map(&:id) if you have such method
GroupMember.where(:user_id => #user.id).all.map(&:group_id)
Also feel free to replace destroy_all with delete_all if you don't need to cleanup after the records.

Advanced find in Rails

I really suck at Rails' finders besides the most obvious. I always resort to SQL when things get more advanced than
Model.find(:all, :conditions => ['field>? and field<? and id in (select id from table)', 1,2])
I have this method:
def self.get_first_validation_answer(id)
a=find_by_sql("
select answers.*, answers_registrations.answer_text
from answers_registrations left join answers on answers_registrations.answer_id=answers.id
where
(answers_registrations.question_id in (select id from questions where validation_question=true))
and
(sale_registration_id=#{id})
limit 1
").first
a.answer_text || a.text if a
end
Can someone create a find method that gets me what I want?
Regards,
Jacob
class AnswersRegistration < ActiveRecord::Base
has_many :answers
end
id = 123
the_reg = AnswersRegistration.first(
:joins => :answers,
:conditions => '(question_id in (select id from questions where validation_question = true)) and (sale_registration_id = ?)', id)
(untested)
Just use binarylogic's Searchlogic gem if that satisfies your need.
Here you go: http://github.com/binarylogic/searchlogic
Sometimes AR will choke on complicated nested conditions, but in theory you should be able to do this:
AnswersRegistration.first(:conditions => { :question => { :validation_question => true },
:sale_registration_id => id },
:include => :answer)

Resources