how do I get rid of sql injection in this case - ruby-on-rails-3

I have a method like this in my RoR 3 app
def buscar
array = params[:query].split(' ')
array.each_with_index do |query, index|
array[index] = array[index].gsub(/<\/?[^>]*>/, "").downcase
end
#noticias = Noticia.where(:tags.all => array).paginate(:page => params[:page])
end
I'm using brakeman to scan for any problems, and he says this
Possible SQL injection near line 116: Noticia.where(:tags.all => (params[:query].split(" ")))
How can I change the query to evict this problem?
Oh, i'm using mongoid
Thanks in advance

This is untested, but something like this:
tag = params[:query].split(" ")
tag.each do |tag|
#noticias << Noticias.find_by_tag(tag)
end
#noticias.paginate(:page => params[:page])
You may have to mess with the <<. I'm not sure what paginate looks for in the #noticias object.

Related

Mongoid dynamic query

This must be an easy one, but I'm stuck...
So I'm using Rails#3 with Mongoid and want to dynamically build query that would depend upon passed parameters and then execute find().
Something like
def select_posts
query = :all # pseudo-code here
if (params.has_key?(:author))
query += where(:author => params[:author]) # this is pseudo-code again
end
if (params.has_key?(:post_date))
query += where(:create_date => params[:post_date]) # stay with me
end
#post_bodies = []
Post.find(query).each do |post| # last one
#post_bodies << post.body
end
respond_to do |format|
format.html
format.json { render :json => #post_bodies }
end
end
You have a few different options to go with here - depending on how complex your actual application is going to get. Using your example directly - you could end up with something like:
query = Post.all
query = query.where(:author => params[:author]) if params.has_key?(:author)
query = query.where(:create_date => params[:post_date]) if params.has_key?(:post_date)
#post_bodies = query.map{|post| post.body}
Which works because queries (Criteria) in Mongoid are chainable.
Alternatively, if you're going to have lots more fields that you wish to leverage, you could do the following:
query = Post.all
fields = {:author => :author, :post_date => :create_date}
fields.each do |params_field, model_field|
query = query.where(model_field => params[params_field]) if params.has_key?(params_field)
end
#post_bodies = query.map{|post| post.body}
And finally, you can take it one level further and properly nest your form parameters, and name the parameters so that they match with your model, so that your params object looks something like this:
params[:post] = {:author => "John Smith", :create_date => "1/1/1970", :another_field => "Lorem ipsum"}
Then you could just do:
#post_bodies = Post.where(params[:post]).map{|post| post.body}
Of course, with that final example, you'd want to sanitize the input fields - to prevent malicious users from tampering with the behaviour.

Rails: accessing the values of columns selected with column_names

Any ideas what it takes to get this to work? I can't for the life of me figure it out.
def get_prices(c)
#print_prices = {}
Billing.where(:name => c).column_names.each do |d|
if d.match(/^print_/)
#print_prices[d] = d.value
end
end
return #print_prices
end
I've got no idea what to substitute d.value for.
Cheers for any help.
The following code will perform the query, returned in the form of a relation, and reject all items in the attribute key-value hash which do not match the given regex, which, in this case, is /^print_/.
def get_prices(c)
Billing.where(:name => c).first.attributes.reject{ |i| !i.match(/^print_/) }
end
Alternatively, it can also be written as:
def get_prices(c)
Billing.where(:name => c).first.attributes.select{ |i| i.match(/^print_/) }
end

Devise Gem and the Geocoder Gem

I am using geocoder and the devise gem. And i am trying to get coupons near user's location
Coupon Model
def index
if params[:search].present?
#coupons = Coupon.near([user_long, user_lat], 50, :order => :distance)
else
#coupons = Coupon.all
end
end
Application Helper
I have defined the user_long and user_lat
def user_long
current_user.longitude
end
def user_lat
current_user.latitude
end
Devise Gem
I have tried to use the devise gem helper to get the values like so
Coupon Model
def index
if params[:search].present?
#coupons = Coupon.near([current_user.longitude, current_user.latitude], 50, :order => :distance)
else
#coupons = Coupon.all
end
end
I am hitting the walls and celling with this. Can someone help out, i know this is newbie question for but i can't solve it so save my life?
You are not seeing anything on the index page because your #coupons array is empty:
#coupons = Coupon.near([current_user.longitude, current_user.latitude], 50, :order => :distance)
In development log (in the same window where rails server is running, if you are running the rails server from console), you should check out the SQL query generated for CouponsController#index action.
Assuming you defined your 'near' query like this:
class Coupon
scope :near, lambda { |longitude, latitude| some logic...
end
You can debug this 'near' method using "rails console" like this:
rails console
> Coupon.near(10, 20)
etc..
My mistake was that i that i had the longitude before that latitude, It was taking away the logic
This works.
def index
#coupons = Coupon.near([current_user.latitude, current_user.longitude], 50, :order => :distance)
end

haml_tag not returning any string

Hi I've tried to copy my old haml_tags and it seems either they are not working for Rails 3.1rc4 or i'm doing somethign wrong. Can anyone point me to the right direction?
def bonus_value_of(stat)
bonus = current_user.character.send("bonus_#{stat}".to_sym)
capture_haml do
haml_tag :span, :class => "positive" do
"+#{bonus}"
end
end
end
thats my code which i call with
= bonus_value_of(stat)
and all i get is a blank span with positive class but no content(not even the plus)
is this a bug?
Here's my version.
1.Your helper should be in controller's helper, not in module Haml::Helper like it was described in some article.
2.Change your helper to this:
def bonus_value_of(stat)
bonus = current_user.character.send("bonus_#{stat}".to_sym)
haml_tag :span, :class => "positive" do
haml_concat "+#{bonus}"
end
end
And then use it in your view like this:
- bonus_value_of(stat)
I just ran into this. I needed to pass my span text as the second value to haml_tag.
def bonus_value_of(stat)
bonus = current_user.character.send("bonus_#{stat}".to_sym)
capture_haml do
haml_tag :span, "+#{bonus}", :class => "positive"
end
end

Will_Paginate and order clause not working

I'm calling a pretty simple function, and can't seem to figure out whats going on. (I'm using rails 3.0.3 and the master branch of 'will_paginate' gem). I have the following code:
results = Article.search(params) # returns an array of articles
#search_results = results.paginate :page => params[:page], :per_page=>8, :order => order_clause
No matter what I make the order_clause (for example 'article_title desc' and 'article_title asc'), the results are always the same in the same order. So when I check using something like #search_results[0], the element is always the same. In my view, they are obviously always the same as well. Am I totally missing something?
I'm sure its something silly, but I've been banging my head against the wall all night. Any help would be much appreciated!
Edited to Add: The search clause does the following:
def self.search(params)
full_text_search(params[:query].to_s).
category_search(params[:article_category].blank? ? '' : params[:article_category][:name]).
payout_search(params[:payout_direction], params[:payout_value]).
length_search(params[:length_direction], params[:length_value]).
pending.
distinct.
all
end
where each of these guys is a searchlogic based function like this:
#scopes
scope :text_search, lambda {|query|
{
:joins => "INNER JOIN users ON users.id IN (articles.writer_id, articles.buyer_id)",
:conditions => ["(articles.article_title LIKE :query) OR
(articles.description LIKE :query) OR
(users.first_name LIKE :query) OR
(users.last_name LIKE :query)", { :query => "%#{query}%" }]
}
}
scope :distinct, :select => "distinct articles.*"
#methods
def self.payout_search(dir, val)
return no_op if val.blank?
send("payment_amount_#{dir.gsub(/\s+/,'').underscore}", val)
end
def self.length_search(dir, val)
return no_op if val.blank?
send("min_words_#{dir.gsub(/\s+/,'').underscore}", val)
end
Thanks.
If you look at the example from the will_paginate github page you can spot one important difference between their use of the :order clause and yours:
#posts = Post.paginate :page => params[:page], :order => 'created_at DESC'
This calls paginate on the Post object (with no objects being selected yet - no SQL has been executed before paginate comes along). This is different in your example: as you state in the first line of code "returns an array of articles". The simplest I can come up with showing the problem is
results = Model.limit(5).all
#results = results.paginate :order => :doesnt_matter_anymore
won't sort, but this will:
results = Model.limit(5)
#results = results.paginate :order => :matters
It should suffice to take the all out of the search method. It makes ActiveRecord actually perform the SQL query when calling this method. Will_paginate will do that for you when you call paginate (if you let it...). Check out the section on Lazy Loading in this post about Active Record Query Interface 3.0