What is the syntax for like in Ruby on Rails? This is something I'm trying to do:
I am trying to find all the last name from table which starts with egm so something like %egm%. I know how to do using find_by_sql but just curious to know the Ruby way.
s = Person.find_by_last_name('nan%')
Person.where('name LIKE ?', '%egm%').all
l_name_var = "nan"
Person.where("people.last_name LIKE :l_name", {:l_name => "#{l_name_var}%"})
or in your case
l_name_var = "egm"
Person.where("people.last_name LIKE :l_name", {:l_name => "%#{l_name_var}%"})
To expand a bit, the find_by_X methods use the = operator, so you wouldn't want to use them for a like condition. The "Rails" way involves using a bit of SQL inside of the where method as shown in the other answers. The same would apply if you're trying to sort your results using the order method.
Related
I am using ruby 1.8.7 and rails 2.3.2
The following code is prone to sql injection
params[:id] = "1) OR 1=1--"
User.delete_all("id = #{params[:id]}")
My question is by doing the following will be the best solution to avoid sql injection or not. If not then what is the best way to do so?
User.delete_all("id = #{params[:id].to_i}")
What about:
User.where(id: params[:id]).delete_all
Ok sorry for Rails 2.x its:
User.delete_all(["id = ?", params[:id]])
Check doc
Btw, be sure you want to use delete_all instead of destroy_all, the former doesn't trigger callbacks.
You can use this also
User.delete(params[:id])
The other answers answer this well for Rails and it'll work fine if you follow their suggestions. In a more generic setting when you have to handle this yourself you can typically use a regular expression to extract a value that's in an expected format. This is really simple with an integer id. Think of it like this:
if params[:id] =~ /(\d+)/
safe_id = $1.to_i
# do something with safe_id now
end
That gets a little more complicated when you're handling strings and arbitrary data. If you have to handle such data then you can use the quoting methods available for the database adapters. In Rails this is ultimately rolled into a consistent interface:
safe_string = ActiveRecord::Base.connection.quote(unsafe_string)
For most database systems this will handle single quotes and backslashes in a special manner.
If you're outside of Rails you will have to use the quoting methods specific to your database adapter, but usage is quite similar.
The takeaway:
If your data has a particular format, enforce the format with a regular expression
Otherwise, use your database adapter's quoting function to make the data "safe" for use in a query
Rails will handle most of this for you if you properly use the various methods and "conditions"
Use the rails methods to pass your where options. You can always hardcode them, as in the example that you give, but the usual way would be something like:
User.where(:id => params[:id]).delete_all
User.where("id = ?", params[:id]).delete_all
User.where("id = :id", :id => params[:id]).delete_all
They are well tested and in case a new vulnerability is detected, an update will fix the problem and your code will not need to be changed.
By the way, if you just want to delete 1 record based on its id, what I would do is:
User.find(params[:id]).destroy
I got a little problem using the LIKE sentence on rails i know that this next sentence works:
Brand.find(:all, :joins=>[:cars], :conditions=>["brandname LIKE ?","%ford%"])
But it's any way around that I could to something like this:
Brand.find(:all, :joins=>[:cars], :conditions=>["brandname LIKE '%ford%'"])
Its because i already have a function that returns all conditions on a single string, but i require to support search in strings and i don't really how to get it work.
Any help will be appreciated.
I'm not entirely certain that I understand what you're talking about. Are you trying to pass in a variable into the conditions?
I would re-write this query just a tad.
Brand.all.joins(:cars).where("brandname LIKE ?", "%#{some_variable}%")
Of course selecting all can be bad for performance if you get a lot of records so you may want to consider limiting that or paginating the results somehow.
I would recommend the guides. Using an array would be great in this instance
Brand.all.joins(:cars).where("brandname LIKE ?", "%#{params[:brand_search]}%")
How can I search first in model (i know how to do this). And then search in this array for more concretence? As you see:
#articles = Article.find(:all, :conditions => { :ART_ID => #search.map(&:ARL_ART_ID)})
#a = #articles.find_all{|item| item.ART_ARTICLE_NR == search.upcase }
First i search in model, but thanks to my db) it have many wrong results, so i must to clarify my array. But there how to search like sql:
like % %
Now it search very strong: if i search AC451, it's good, but if AC45 or C451 it's nothing fetches. How to say him so that before and after
search
could be everything?
Like this, maybe?
item.ART_ARTICLE_NR.include?(search.upcase)
You are asking for trouble by not following rails naming conventions an using upper case column names. That said, the rails3 way to do it is probably:
#articles = Article.where(:ART_ID => #search.map(&:ARL_ART_ID)).where('ART_ARTICLE_NR LIKE', "%#{search.upcase}%")
Without knowing what #search is, it's hard to be sure. But you should read up on the active record guide on the rails 3 query format.
It's maybe not straigtforward answer, but have you considered using ransack gem?
Is it possible to query unsaved changes using Rail's ActiveRecord or another similar approach?
An example of a Ruby interactive session is below. What I'd like to see, is the fourth line show a result of '999' instead of '10'. I'm use to using .NET and Entity Framework where something similar to this was possible. Perhaps in Ruby there is a better or different way to do the same thing. I could obviously add up the sum in a loop, but I find the query syntax more elegant. Any help is appreciated.
i = Inventory.where(:product_id => 1)
i.sum(:available) => 10
i.first.available = 999
i.sum(:available) => 10
No, since sum() is actually translated to SQL and run on the db, you must save the record to the db in order for the query to return the result you want.
Alternatively, you can use the Enumerable#sum method in ActiveSupport, which takes a block, like so:
all = Inventory.where(:product_id => 1).to_a
all.first.available = 999
all.sum(&:available)
I want to do
current_user.field = User::?????????
Where ?????????? would be whatever I wanted it to be
This what I'm trying to do
Given /^"([^\"]*)" is a(?:|n) "([^\"]*)"$/ do |arg1, arg2|
cur_user = User.find(:first, :conditions => ['name = ?', arg1])
cur_user.update_attributes(:role => User::arg2.constantize)
end
While constantize does't work for this use, I do know that it would work In Object.var.constantize context
What's the problem you're trying to solve? Using constants this way is a code smell, you should probably be using something like ActiveHash if you've got a set of Enumeration values or something that's configuration to walk through.
If you do need to solve your problem this way, check out const_defined?() and const_get() for this. const_get() will allow you to do a dynamic value call on a symbol/string constant name without constantizing it.
http://ruby-doc.org/core/classes/Module.html#M001689
Either use:
"User::#{arg2}".constantize
or
User.const_get(arg2)
Use
????????.constantize
you can do any thing