trouble with some data management code in my sessions_controller - ruby-on-rails

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.

Related

Rails How to use join in this specific situation?

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?

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.

Problem with activerecord find

I have 5 tables and they related between. Everythings good, perfectly! But i tried to make script, than if in inquiry table field is_answered = 0, so i find respondents (by respondent_id in question table) and send them letter
BUT
I HAVE MISTAKE!
I have this code:
inquiry = Inquiry.find(:all, :conditions => ["is_answered = 0"])
question = inquiry.question
respondents = Respondent.find(:all, :conditions => ["id = (?)", question.user_id])
respondents.each do |r|
Notifier.deliver_user_notification(inquiry)
end
And when i typing ruby blah.rb i get this error:
undefined method `question' for #<Array:0x7f646c82b568>
What my mistake?
PS - Inquiry table (id, question_id, respondent_id) relationship table between questions and answers.
PSS - Respondent table related with Inquiry.
The problem is that you have more inquiry so the following returns an array.
Inquiry.find(:all, :conditions => ["is_answered = 0"])
Try the following, but be mindful of how many sql queries it does, as there are probably optimisations that can be made:
inquiry = Inquiry.find(:all, :conditions => ["is_answered = 0"])
inquiry.each do |i|
question = i.question
respondents = Respondent.find(:all, :conditions => ["id = (?)", question.user_id])
respondents.each do |r|
Notifier.deliver_user_notification(inquiry)
end
end

Complex filtering based on a many-to-many relationship

In my application, Annotations are considered "accepted" if either:
They have been explicitly marked "accepted" (i.e., their state == 'accepted')
They were last updated by a user who has the "editor" role
My question is how to find all accepted explanations with a single DB query. Basically I'm looking for the database-driven version of
Annotation.all.select do |a|
a.last_updated_by.roles.map(&:name).include?('editor') or a.state == 'accepted'
end
My first attempt was
Annotation.all(:joins => {:last_updated_by => :roles}, :conditions => ['roles.name = ? or annotations.state = ?', 'editor', 'accepted'])
But this returns a bunch of duplicate records (adding a .uniq makes it work though)
Changing :joins to :include works, but this makes the query way too slow
Are the results of your first attempt just wrong or do they only need an ".uniq"?
Have you tried
:include => {:last_updated_by => [:roles]}
instead of the join?
or making two queries
#ids = Editor.all(:conditions => ["role = 'editor'"], :select => ["id"]).map{|e|e.id}
Annotation.all(:conditions => ["last_updated_by in (?) or state = ?", #ids.join(","), "accepted"]
is that any faster?

Association : client.order , ok but how do you retrieve the client from the order?

I have read the following rails guide : http://guides.rails.info/active_record_querying.html
in there exemple a client has many orders and orders belong to clients.
They explain how to find a lot of stuff from client. But if i want all orders from yesterday, with the corresponding client name, how do i retrieve the client from an order?
# controller
#orders = Order.all(:include => :client,
:conditions => ["created_at = ?", Date.today-1])
# view
<% #orders.each do |order| %>
<%= order.client.name %>
<% end %>
Edit:
If you have an specific order id, you can do your search like
#order = Order.first(id, :include => :client)
and access the client the same way
#order.client.name
today = Date.today
yesterday = today - 1.days
orders = Order.find(:all, :include => :client, :conditions => ["created_at >= :yesterday AND created_at <= :today", {:yesterday => yesterday, :today => today}])
You can now iterate orders and do order.client to retrieve the Client object. The :include => :client will make RoR automatically include the it in the query (rather than lazy loading).
You can do something like this:
orders = Order.all(:conditions => ["DATE(created_at) = DATE(?)",
:include => :client,
Time.now - 1.day])
client = orders.first.client

Resources