I have a search form which contains parameters such as city,building_type,min_price,max_price.
What is the best way to chain all those queries together. If the user doesn't set a parameter, I want it to just return all records.
Something like
city=params[:city] || "all"
building_type=params[:building_type] || "all"
min_price=params[:min_price] || "all"
#results= Property.where(city: city,building_type: building_type,min_price: min_price)
Is it possible to do something like this? Seeing that there is no "all" keyword.
You can chain active record queries by assigning the results of all the queries you want to do in a single variable
properties = Property.all
properties = properties.where(city: params[:city]) if params[:city].present?
properties = properties.where(building_type: params[:building_type]) if params[:building_type].present?
Moreover, if the parameter keys are the same as the columns in your database, you can just place all of them in an array and loop through it like
properties = Property.all
%i[city building_type min_price].each do |column_name|
next if params[column_name].blank?
properties = properties.where(column_name => params[column_name])
end
NOTE
The first line, properties = Property.all assumes that it returns an ActiveRecord::Relation object which is the default in Rails 4 (not sure). If you are using Rails 3, just use Property.
Related
i think i used the right terminology for what i need, i currently have a database call in my home_controller that is returning a call to my database with all the entries in that table specified, Freelancer.
There is an attribute on these records that has either a true or false value, which is "featured".
I need a way to call a sort method, or some other way, on that object with the true being first and then the false being afterwards, i tried using this code
def index
#freelancers = Freelancer.all
p 'below im outputting featured freelancer i hope'
#freelancers.sort_by { |row| [row.featured ? 0 : 1, row.id]}
p #freelancers
end
But unfortunately this did not work, can anyone advise me on a way to get this to work? Id rather have the sorted object returned as is, rather then assigning it to a new one. Just for future features of adding pagy and a filter by cost.
Use order method
def index
#freelancers = Freelancer.order(featured: :desc)
end
The title is a bit confusing, so let me explain.
I have 3 Model classes called Table1, Table2, and Table3. All three tables have the "total" column.
This is what I want to be able to do:
index = either 0, 1, or 2
tableNames = ["Table1", "Table2", "Table3"]
tableNames[index].total
^ Obviously I can't do that because tableNames[index] returns a string, not a reference to the actual class itself.
This is what I'm currently doing:
index = either 0, 1, or 2
if index == 0 then
Table1.total
elsif index == 1 then
Table2.total
elsif index == 2 then
Table3.total
end
I guess what I want to do is a bit analogous to the "send" method in ruby, where you can use variables as method names.
Is there a way to do this, or do I have to do the if elsif check? This makes the code longer and clunkier and I'm wondering if there's a better way. Thanks!
If you are getting the model name as a string. You can do this
model_name = "Table1" #or "Table2", "Table3"
model = model_name.constantize
model.total
You can directly turn any string into a class with constantize method.
Note - If you are going to use rails further, ideally refer to them as Models not tables.
I have this to find a DB Entry with the key field the same as the ID params. Now, I get this:
undefined method `confirmed=' for<ActiveRecord::Relation::ActiveRecord_Relation_Email:0x007fd5254c33d8>
And the code:
key = Email.where(:key => params[:id])
if key[1] = nil
#error = true
else
key.confirmed = true
#error = false
end
I was expecting to get a nil if it wasn't in the DB or a Email Object. I was also thinking it could return a hash of Email objects. There should be 0 or 1 DB Entrys. How should I do this correctly? I have no idea what a ActiveRecord::Relation is.
Email.where return multiple records. What you actually want to use is Email.find_by which will allow you to pass a hash of conditions you want the record to match (like how Email.where works), but will return either the first record found, or nil. Your conditional will need to change as a result
You seem to get it completely wrong. Please get acquainted with ActiveRecord documentation.
ActiveRecord::Relation represents query results. Yes, you can update records through it, but this way:
key.update_all(confirmed: true)
which will update confirmed attribute on all records found by the query.
If you want to check whether it has returned at least one record, use:
if key.first
...
To update this one record only:
key.first.confirmed = true
key.first.save
or:
key.update_attribute(:confirmed, true)
I'm trying to do something like:
if filter_1
#field = #field.where()
else
#field = #field.where()
end
if filter_2
#field = #field.order()
end
etc.
But how do I init #field with an empty query? I tried #field = Field.all but that gives an array so not allowing chaining.
Try scopedon Model class e.g.
#fields = Field.scoped
#fields = #fields.where("your conditions") if filter_1
#fields = #fiels.order("your conditions") if filter_2
The first time you are initializing the #field instance variable, Please try referring to the class Field, i.e.
Filter1: #field = Field.where(...)
Afterwards if you need to keep adding further filters you can refer to your variable field as many times as you want to.
Filter2 onward: #field = #field.where(...)
As Filter1 would return an active Record relation, you can nest more condition clauses onto it. Also do not worry about performance issues as the SQL will only be generated and processed once it is actually needed.(lazy loading)
If you to #field.to_sql at the end of your filters, you'll be able to see that all of your where clauses have conveniently been nested together into one SQL statement.
Also, I'd recommend you to read Active Record Query Interface
EDIT
Create a method get_field. And use that to add filter results.
def get_field(field)
#field.is_a?(ActiveRecord::Relation) ? Field : field
end
get_field(#field).where(....)
get_field(#field).where(....)
Given a query like:
current_user.conversations.where("params[:projectid] = ?", projectid).limit(10).find(:all)
params[:projectid] is being sent from jQuery ajax. Sometimes that is an integer and the above works fine. But if the use selects "All Projects, that's a value of '' which rails turns into 0. which yields an invalid query
How with rails do you say search params[:projectid] = ? if defined?
Thanks
I think you may have mistyped the query a bit. "params[:projectid] = ?" shouldn't be a valid query condition under any circumstances.
In any case, you could do some sort of conditional statement:
if params[:project_id].blank?
#conversations = current_user.conversations.limit(10)
else
#conversations = current_user.conversations.where("project_id = ?", params[:project_id]).limit(10)
end
Although, I'd probably prefer something like this:
#conversations = current_user.conversations.limit(10)
#converstaions.where("project_id = ?", params[:project_id]) unless params[:project_id].blank?
Sidenotes:
You don't have to use .find(:all). Rails will automatically execute the query when the resultset is required (such as when you do #conversations.each).
Wherever possible, try to adhere to Rails' snakecasing naming scheme (eg. project_id as opposed to projectid). You'll save yourself and collaborators a lot of headaches in the long run.
Thanks but if the where query has lets say 3 params, project_id, project_status, ... for example, then the unless idea won't work. I'm shocked that Rails doesn't have a better way to handle conditional query params
EDIT: If you have multiple params that could be a part of the query, consider the fact that where takes a hash as its argument. With that, you can easily build a parameter hash dynamically, and pass it to where. Something like this, maybe:
conditions = [:project_id, :project_status, :something_else].inject({}) do |hsh, field|
hsh[field] = params[field] unless params[field].blank?
hsh
end
#conversations = current_user.conversations.where(conditions).limit(10)
In the above case, you'd loop over all fields in the array, and add each one of them to the resulting hash unless it's blank. Then, you pass the hash to the where function, and everything's fine and dandy.
I didn't understand why you put:
where("params[:projectid] = ?", projectid)
if you receive params[:project] from the ajax request, the query string shouldn't be:
where("projectid = ?", params[:projectid])
intead?
And if you are receiving an empty string ('') as the parameter you can always test for:
unless params[:projectid].blank?
I don't think i undestood your question, but i hope this helps.