In Ruby on rails 3 I want to query on a has_many field of a model as follows:
#project.items.where(:status => 1)
The problem is I'm trying to get the exact opposite result than this. What i want is all items of #project where the status is not 1. Been looking for the answer to this for a while, anyone?
There are many ways to accomplish what you are trying to do, however, some are better than others. If you will always be searching for a hardcoded number (i.e. 1 in this case), then the following solution will work:
#project.items.where('status != 1')
However, if this value is not hard-coded, you are openly vulnerable to SQL injection as Rails will not (cannot) escape this kind of query. As a result, it is preferred among Rails developers to user the following syntax for most custom conditions (those that can't be constructed via Hash):
#project.items.where(['status != ?', 1])
This syntax is slightly confusing, so let me go over it. Basically you are providing the where clause an Array of values. The first value in the array is a String representing the query you want executed. Anywhere you want a value in that string, you place a ?. This serves as a placeholder. Next, you add an element for every question mark in you query. For example, if I had the following:
where(['first_name = ? AND last_name = ?', params[:first_name], params[:last_name]]
Rails will automatically match these up forming the query for you. In that process, it also escapes potentially unsafe characters, preventing injection.
In general, it is preferred to use the Array syntax, even for a hardcoded value. I've been told that pure string conditions in Rails 3.5 will raise a warning (unverified), so it doesn't hurt to get in the process of using the Array syntax now.
Related
I am using Rails 4 and I need to use find_by_sql in my active record model.Now I am facing two serious problems. First one is that it does not give me a particluar data whether it is giving #Employee:0x0000000b2a1718 as result. My model name is Employee and tbale name is employees. I am using pg.
Please tell me is there any solution.
Second problem is that how can I write any rails variable with in the sql query used in find_by_sql. For example I want to execute find_by_sql("select firstname from employee where id=#var"), where #var is a ruby variable.
The actual query I need to execute is select firstname from employee where comapact_string like %#var% using find_by_sql.
There's degrees of customization when making a query. The simplest form is where you can use the built-in finders:
Employee.where(id: #var).pluck(:first name)
That will do a direct match, and if one's found, give you the first_name column value. No model is produced with pluck.
If you want to do an approximate match with LIKE you write out the WHERE clause more formally:
Employee.where('id LIKE ?', "%{#var}%").pluck(:first_name)
It's rare you need to write out an entire query with find_by_sql, but if you do you must be extremely cautious about what data you put in the query. It's strongly recommended to use placeholder values whenever possible, and if you absolutely must bypass this, escape everything no matter the source.
I ask because a thorough Google search returns no clue as to how to do this.
I am trying to pull an example of a column field which is rarely used and is unfortunately littered with newlines and dashes even in empty ones, so I can't just ask for ones that have data. I need to ask for a column that has at least 10-15 characters or something like this. I can also imagine this query being useful for validating pre-existing data. I know about the validator that does this, but I'm not trying to validate, I'm trying to search.
Thanks!
Seems ActiveRecord does not support this. But you can do it anyway like (Mysql example)
Model.where("CHAR_LENGTH(text_field) = ?", 10)
in Postgres the same should work but in documentation it says to use char_length()
Also what you could do is on saving the record store the size of the field with a callback
before_save {|r| r.text_field_size = r.text_field.size}
With this you can now query with that, wich will be DB agnostic.
Model.where(text_field_size: 10)
I think you'll have to write so part of the request in SQL.
For MySQL, use something like :
Model.where("CHAR_LENGTH(field_name) >= ?", min_length)
We have an SQL query in our Rails 3 app.
#followers returns an array of IDs of users following the current_user.
#followers = current_user.following
#feed_items = Micropost.where("belongs_to_id IN (?)", #followers)
Is there a more efficient way to do this query?
The query you have can't really be optimized anymore than it is. It could be made faster by adding an index to belongs_to_id (which you should almost always do for foreign keys anyway), but that doesn't change the actual query.
There is a cleaner way to write IN queries though:
Micropost.where(:belongs_to_id => #followers)
where #followers is an array of values for belongs_to_id.
It looks good to me.
However if you're looking for real minimum numer of characters in the code, you could change:
Micropost.where("belongs_to_id IN (?)", #followers)
to
Micropost.where("belongs_to_id = ?", #followers)
which reads a little easier.
Rails will see the array and do the IN.
As always the main goal of the ruby language is readability so little improvements help.
As for query being inefficent, you shuld check into indexs on that field.
They tend to be a little more specific for each db - you have only specified generic sql. in your question.
In Rails 3.1, how would you go about making a query string appear cleaner and more readable.
For example, the Rails default for a key with multiple parameters in the query string would appear like:
/clients?ids[]=1&ids[]=2&ids[]=3
I want it to appear like:
/clients?ids=1,2,3
or even
/clients?ids=1|2|3
The ids are controlled by a series of links that act as filters for selecting 1 or more options for filtering on some search results.
What would be the best way to go about this?
The only way you could do it automatically is by monkeypatching something in Rack or Rails. You should avoid doing that as it's going to cause more issues than it solves.
If you have a string that embeds a | or , then you could have it incorrectly converting data. Or if you only have one entry such as ids=1 it wouldn't know to convert it into an array with just 1 inside.
You would be better off doing this manually whenever you need to pass an array that needs to be cleaned up. In this case, you would just call ids.join(",") when passing it to the router method and params[:ids].split(",") to get an array back out.
I would like to have a method called feed in my User model that returns all the entries from two tables (discussions, exchanges).
In User.rb
def feed
SELECT * FROM discussions, exchanges GROUP BY created_at
end
This doesn't work, i get a problem in rails console
syntax error, unexpected ';', expecting '='
Can anyone show me how to write SQL in here? Basically I want to return and sort entries from two different tables..
if you want actual ActiveRecord objects you can try the following
def feed
exchanges = Exchange.all
discussions = Discussion.all
(exchanges + discussions).sort! { |a, b| a.created_at <=> b.created_at }
end
this is quite ineffective, as the sorting could be done in sql, but ActiveRecord cannot instantiate records selected from different tables (you can somehow override this by using STI)
Firstly - you can't just write plain SQL in your ruby code and expect it to work.
It's ruby, not SQL. They are different languages.
If you can - use the ruby-way with associations instead (as per the other example).
However - if you desperately need to use raw SQL (eg you have legavy tables that don't match to models or have some complex combination-logic in teh SQL that doesn't easily map to assocations); then you need to pass SQL to the database... which means using a connection via Active Record.
Try:
def feed
ActiveRecord::Base.connection.execute("SELECT * FROM discussions, exchanges GROUP BY created_at")
end
It will not return ruby models for you - just a raw results-object.
I'd recommend trying this in script/console and then doing a "puts my_user.feed.inspect" to have a look at the kind of thing it returns so you know how to use it.
Note: the presence of this kind of thing is considered a strong code smell - only use it where you really need it