Rails ActiveRecord::Relation error - ruby-on-rails

Looking into passing a variable as value on ActiveRcord query key/column?
login = Login.where("email_address" => "geo#bostj.com","active" => 1).select("id")
=> [#<Login id: 767>]
login = Login.where("email_address" => "geo#bostj.com","active" => 1).select("id").class
=> ActiveRecord::Relation
admin = Admin.where("login_id"=>login).exists?
Heeeelp

I would do:
login = Login.where(email_address: 'geo#bostj.com', active: 1)
Admin.exists?(login_id: login.pluck(:id))

You can write as
login_ids = Login.where("email_address" => "geo#bostj.com","active" => 1).pluck(:id)
Admin.where("login_id in (?)", login_ids).blank?
blank?
Returns true if relation is blank.
Admin.where("login_id in (?)", login_ids) gives back us ActiveRecord::Relation object, so I think we can use #blank? method.

It should be
admin = Admin.where("login_id" => login.first.id).exists?

Related

Where function equivalent for eager loading in rails

I am trying to optimize my code with eager loading, but when ever where function is called, a query is executed in logs.
#votes_list = Vote.joins(:user => :profile).where(:post_id => post.id)
#male_votes = #votes_list.where(:profiles => { :gender => 1 }).count
#female_votes = #votes_list.where(:profiles => { :gender => 2 }).count
I am trying to make few queries after the first one, without need to fetch from database, how to do it?
You want to eagerly load the Users and their Profile for each vote. Then you can select the sub-set of votes in-memory broken down by gender on the profile.
#votes_list = Vote.where(:post_id => post.id, :include => { :user => :profile })
#male_votes = #votes_list.select {|v| v.user.profile.gender == 1}
#female_votes = #votes_list.select {|v| v.user.profile.gender == 2}

Return nil if no current_user

I have the following Scope in my Rails app, which is used to fetch active Choices from the database based on the current_user. This works just fine, but if there is no current_user the the code fetches alle the Choices in the database. Here I just want it to fetch nothing.
scope :active, lambda{|user| user ? { :conditions => ["deliverydate = ? and user_id = ?", Date.tomorrow, user.id], :order => 'id DESC'} : {} }
How do I rewrite thee above to return nothing if there is no current_user?
The problem is that I'm using Pusher to push new data to the website, but if the user session expires then all data are pushed instead of nothing.. hopes this makes sense :)
As scopes return an ActiveRecord::Relation instance so it would be more correct to return empty ActiveRecord::Relation object like it's described here.
So, you have to add :none scope which does the trick:
scope :none, limit(0)
and then use it inside your scope like:
scope :active, ->(user = nil) { user ? { :conditions => ["deliverydate = ? and user_id = ?", Date.tomorrow, user.id], :order => 'id DESC'} : none }
scope :active, lambda{|user| user ? { :conditions => ["deliverydate = ? and user_id = ?", Date.tomorrow, user.id], :order => 'id DESC'} : nil }
That is because the empty hash ({}) has no conditions, which basically means return all rows.
Based on the way your code is structured, you could make a condition that is something like :id => -1, :id => nil or 1=0 or something that is always false so it won't return any rows.
(And as was mentioned in the comment below your question, scopes should not return nil since it cannot be chained.)

Search ignoring certain blank parameters

I have a simple search action that has 3 parameters and a where method to search a model. If I search and some of the parameters are nil, it will not return the records I want. I want it to search the database by only using the parameters that are not nil/blank. So if only one category is entered and sent in the parameters, I want my controller to ignore the other two parameters. However, if the other parameters are present, I want them to be included in the search.
I've tried many approaches but I can't get it to work properly. Here's my code.
hash = []
cat = :category_id => params[:category_id]
col = :color_id => params[:color_id]
brand = :brand_id => params[:brand_id]
if params[:category_id].present?
hash += cat
end
if params[:color_id].present?
hash += col
end
if params[:brand_id].present?
hash += brand
end
#results = Piece.where(hash).preload(:item).preload(:user).group(:item_id).paginate(:page => params[:page], :per_page => 9)
I've put the variables into strings and hashs, called to_a, joined them with (","). Nothing works.
Thanks
Try this code.
criteria = { :category_id => params[:category_id], :color_id => params[:color_id],
:brand_id => params[:brand_id] }.select { |key,value| value.present? }
#results = Piece.where(criteria).preload(:item).preload(:user).group(:item_id).
paginate(:page => params[:page], :per_page => 9)

check_box_tag and find condition

<%= check_box_tag('videos_count')%>
If this box is checked, the param will say "videos_count"=>"1" . In the controller I have this:
videos_count = params[:videos_count]
#cars = Car.paginate( :page => params[:page], :per_page => 10,
:conditions => ["videos_count = ?", videos_count],
when the box is checked I see the correct parameter in the server log, but the find returns all of the results instead of results with videos_count = 1.
Check the datatype of 'videos_count' if it's Tiny INT then following may worh. No checked though.
:conditions => ["videos_count = ?", true]
What will the output for this?
:conditions => ["videos_count = ?", 1])
I think there is an issue with your table.

Filtering ActiveRecord queries in rails

I'm used to Django where you can run multiple filter methods on querysets, ie Item.all.filter(foo="bar").filter(something="else").
The however this is not so easy to do in Rails. Item.find(:all, :conditions => ["foo = :foo", { :foo = bar }]) returns an array meaning this will not work:
Item.find(:all, :conditions => ["foo = :foo", { :foo = 'bar' }]).find(:all, :conditions => ["something = :something", { :something = 'else' }])
So I figured the best way to "stack" filters is to modify the conditions array and then run the query.
So I came up with this function:
def combine(array1,array2)
conditions = []
conditions[0] = (array1[0]+" AND "+array2[0]).to_s
conditions[1] = {}
conditions[1].merge!(array1[1])
conditions[1].merge!(array2[1])
return conditions
end
Usage:
array1 = ["foo = :foo", { :foo = 'bar' }]
array2 = ["something = :something", { :something = 'else' }]
conditions = combine(array1,array2)
items = Item.find(:all, :conditions => conditions)
This has worked pretty well. However I want to be able to combine an arbitrary number of arrays, or basically shorthand for writing:
conditions = combine(combine(array1,array2),array3)
Can anyone help with this? Thanks in advance.
What you want are named scopes:
class Item < ActiveRecord::Base
named_scope :by_author, lambda {|author| {:conditions => {:author_id => author.id}}}
named_scope :since, lambda {|timestamp| {:conditions => {:created_at => (timestamp .. Time.now.utc)}}}
named_scope :archived, :conditions => "archived_at IS NOT NULL"
named_scope :active, :conditions => {:archived_at => nil}
end
In your controllers, use like this:
class ItemsController < ApplicationController
def index
#items = Item.by_author(current_user).since(2.weeks.ago)
#items = params[:archived] == "1" ? #items.archived : #items.active
end
end
The returned object is a proxy and the SQL query will not be run until you actually start doing something real with the collection, such as iterating (for display) or when you call Enumerable methods on the proxy.
I wouldn't do it like you proposed.
Since find return an array, you can use array methods to filter it, on example:
Item.find(:all).select {|i| i.foo == bar }.select {|i| i.whatever > 23 }...
You can also achive what you want with named scopes.
You can take a look at Searchlogic. It makes it easier to use conditions on
ActiveRecord sets, and even on Arrays.
Hope it helps.
You can (or at least used to be able to) filter like so in Rails:
find(:all, :conditions => { :foo => 'foo', :bar => 'bar' })
where :foo and :bar are field names in the active record. Seems like all you need to do is pass in a hash of :field_name => value pairs.

Resources