ruby rails converting params to int array - ruby-on-rails

I am sending data via get and I need to put it into a int array to be used in a find.
here is my code :
#found = Array.new
params['candidate'].each do |c|
#found << c.to_i
end
My url looks like this
http://localhost:3000/export/candidate?candidate[]=3&candidate[]=4&commit=Export
If it makes any difference I am using it for this find
#candidate = Candidate.find(:all, :conditions => ["candidates.id IN ?", #found])
But currently it doesn't put it in a real array because I get this error
Mysql::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '4)' at line 1: SELECT * FROM `candidates` WHERE (candidates.id IN 4,2)
The brackets are missing around the array
Thanks and good morning!
Alex

Just put parentheses around your ?
#candidate = Candidate.find(:all, :conditions => ["candidates.id IN (?)", #found])
Also, your first snippet can be collapsed down to:
#found = params['candidate'].map(&:to_i)

The entire conversion you are making is unnecessary. You can pass the string array as a input to the query (as long as the string values represent numbers).
You can get what you need in one line:
Candidate.find_all_by_id(params[`candidate`])
Which is same as:
Candidate.find(:all, :conditions => {:id => params[`candidate`]})
Which is same as:
Candidate.find(:all, :conditions => ["id IN (?)",params[`candidate`]])
Your original attempt did not work because you did not put brackets after the IN clause.

Related

How can I select the minimummonths value?

In SQL I would do this:
SELECT minimummonths WHERE name = "gold"
I want to do the same in Ruby on Rails and have the following in the new section of my orders controller:
#plan = params[:plan]
#Payplanrow = Payplan.where(:name => #plan).minimummonths
I then try to display #payplanrow in my page using <%=#Payplanrow %> but it doesnt work. I get the error:
undefined method `minimummonths' for #<ActiveRecord::Relation:0x007fe30f870ec0>
I want to print the minimummonths value for the plan selected. There will only ever be one row of data corresponding to the #plan value.
I'm pretty new to Ruby on Rails so I'm just trying to get a pointer in the right direction. I looked everywhere but there doesn't seem to be an example of this.
The problem is Payplan.where(:name => #plan) is returning an array of Payplan objects. Assuming you are using Rails 3, you can read more about it in "Active Record Query Interface".
But, if you are certain that your query is returning only one record you could do:
#Payplanrow = Payplan.where(:name => #plan).first.try(:minimummonths)
The Rails way is to have a scope in your model:
class Payplan < ActiveRecord::Base
scope :by_name, lambda {|name|
{:conditions => {:name => name}}
}
end
#controller
#Payplanrow = Payplan.by_name(#plan).first.try(:minimummonths)
Although it's not really optimal, you can do:
#Payplanrow = Payplan.where(:name => #plan).first.minimummonths
You can use pluck to get only the minimummonths value :
minimummonths = Payplan.where(:name => #plan).pluck(:minimummonths).first
Instead of using where then first, it's better to use find when you are expecting a single record.
#Payplanrow = Payplan.find_by_name(#plan).try(:minimummonths)
That should be:
Payplan.where(:name => #plan).first.minimummonths

What does Rails ActiveRecord find return

I'm using the find method as follows:
#records = Effort.find( :all,
:select => 'full_name, taskType, sum(hours)',
:group => 'full_name, taskType',
...
#records.each do |record|
The query works fine. What I am confused about is how to access the sum(hours) value. I've tried the following:
record.sum(hours) # undefined local variable hours
record.sum_hours # sum_hours undefined
record[2] # Gives empty string
record[3] # Same, just double checking where the index might start...
I'm a bit stuck how to access the value! If I add <%= debug #records %> to my view, I see debugging output such as this:
---
- !ruby/object:Effort
attributes:
full_name: admin
taskType: Pre-Sales
sum(hours): '16'
What exactly are you trying to achieve with this query? Are you trying to get the sum of all Effort's hours or group them by some other means?
The query below
#records = Effort.find( :all,
:select => 'full_name, taskType, sum(hours)',
...
Will only ever return 1 value, because you're selecting a sum(hours) in there, which results in SQL aggregating the results into the first row. This means you'll always get your first Effort row, with a sum(hours) field set to the total amount of hours spent on all efforts.
If you just want the sum of all Effort hours, you can do this:
Effort.sum(:hours)
If you're looking to sum hours based on some other criteria, please update your question.
EDIT
In this case you could do something like this,
#records = Effort.group(:full_name, :taskType).sum(:hours)
You'll end up with a hash that looks like this:
[full_name, taskType] => count
i.e.
['baking cookies', 'baking'] => 12
['baking cakes', 'baking'] => 2
...
You could iterate over it like:
#records.each do | (full_name, task_type), hours |
puts 'Full Name: #{full_name}, Task Type: #{task_type}, Total Hours: #{hours}'
end
While looking back at my post and the debug output, it suddenly occurred to me it is right there on the page:
record.attributes[ 'sum(hours)' ]
I suppose that stuff like record.full_name is really a convenience method for accessing the attributes array?
not sure if it works, but you might want to try this :
#sums = Effort.sum(:hours,
:group => [:project_task_id, :user_id],
:joins => [:project_task, :user])
it should give you an array of records. You should then normally be able to collect these:
#array = #sums.collect do |aggregate|
[aggregate.project_task.name, aggregate.user.name, aggregate.hours]
end

Separating an Array into a comma separated string with quotes

I'm manually building an SQL query where I'm using an Array in the params hash for an SQL IN statement, like: ("WHERE my_field IN('blue','green','red')"). So I need to take the contents of the array and output them into a string where each element is single quoted and comma separated (and with no ending comma).
So if the array was: my_array = ['blue','green','red']
I'd need a string that looked like: "'blue','green','red'"
I'm pretty new to Ruby/Rails but came up with something that worked:
if !params[:colors].nil?
#categories_array = params[:colors][:categories]
#categories_string =""
for x in #categories_array
#categories_string += "'" + x + "',"
end
#categories_string.chop! #remove the last comma
end
So, I'm good but curious as to what a proper and more consise way of doing this would look like?
Use map and join:
#categories_string = #categories_array.map {|element|
"'#{element}'"
}.join(',')
This functionality is built into ActiveRecord:
Model.where(:my_field => ['blue','green','red'])
Are you going to pass this string on to a ActiveRecord find method?
If so, ActiveRecord will handle this for you automatically:
categories_array = ['foo', 'bar', 'baz']
Model.find(:all, :conditions => ["category in (?)", categories_array])
# => SELECT * FROM models WHERE (category in ('foo', 'bar', 'baz'))
Hope this helps.
If you are using the parameter hash you don't have to do any thing special:
Model.all(:conditions => {:category => #categories_array})
# => SELECT * FROM models WHERE (category in ('foo', 'bar', 'baz'))
Rails (actually ActiveSupport, part of the Rails framework) offers a very nice Array#to_sentence method.
If you are using Rails or ActiveSupport, you can call
['dog', 'cat', 'bird', 'monkey'].to_sentence # "dog, cat, bird, and monkey"

Is it possible to have variable find conditions for both the key and value?

I'm trying to pass in both the field and the value in a find call:
#employee = Employee.find(:all,
:conditions => [ '? = ?', params[:key], params[:value].to_i)
The output is
SELECT * FROM `employees` WHERE ('is_manager' = 1)
Which returns no results, however when I try this directly in mysqsl using the same call without the '' around is_manager, it works fine. How do I convert my params[:key] value to a symbol so that the resulting SQL call looks like:
SELECT * FROM `employees` WHERE (is_manager = 1)
Thanks,
D
If you want to convert a string to symbol(which is what params[:key] produces, all you need to do is
params[:key].to_s.to_sym
2 points:
A word of caution : symbols are
not garbage collected.
Make sure your key is not a
number, if you convert to_s first
then to_sym, your code will work but
you may get a wierd symbol like
this:
:"5"
You could use variable substitution for column name instead of using bind values:
# make sure the key passed is a valid column
if Employee.columns_hash[params[:key]]
Employee.all :conditions => [ "#{params[:key]} = ?", params[:value]]
end
You can further secure the solution by ensuring column name passed belongs to a pre selected set.:
if ["first_name", "last_name"].include? [params[:key]]
Employee.all :conditions => [ "#{params[:key]} = ?", params[:value]]
end
"string".to_sym

How can I reduce repetition in this Ruby on Rails code?

This is a snippet of code from an update method in my application. The method is POSTed an array of user id's in params[:assigned_ users_ list_ id]
The idea is to synchronise the DB associations entries with the ones that were just submitted, by removing the right ones (those that exist in the DB but not the list) and adding the right ones (vise-versa).
#list_assigned_users = User.find(:all, :conditions => { :id => params[:assigned_users_list_id]})
#assigned_users_to_remove = #task.assigned_users - #list_assigned_users
#assigned_users_to_add = #list_assigned_users - #task.assigned_users
#assigned_users_to_add.each do |user|
unless #task.assigned_users.include?(user)
#task.assigned_users << user
end
end
#assigned_users_to_remove.each do |user|
if #task.assigned_users.include?(user)
#task.assigned_users.delete user
end
end
It works - great!
My first questions is, are those 'if' and 'unless' statements totally redundant, or is it prudent to leave them in place?
My next question is, I want to repeat this exact code immediately after this, but with 'subscribed' in place of 'assigned'... To achieve this I just did a find & replace in my text editor, leaving me with almost this code in my app twice. That's hardly in keeping with the DRY principal!
Just to be clear, every instance of the letters 'assigned' becomes 'subscribed'. It is passed params[:subscribed_ users_ list_ id], and uses #task.subscribed_ users.delete user etc...
How can I repeat this code without repeating it?
Thanks as usual
You don't need if and unless statements.
As for the repetition you can make array of hashes representing what you need.
Like this:
[
{ :where_clause => params[:assigned_users_list_id], :user_list => #task.assigned_users} ,
{ :where_clause => params[:subscribed_users_list_id], :user_list => #task.subscribed_users}
] each do |list|
#list_users = User.find(:all, :conditions => { :id => list[:where_clause] })
#users_to_remove = list[:user_list] - #list_users
#users_to_add = #list_users - list[:user_list]
#users_to_add.each do |user|
list[:user_list] << user
end
#users_to_remove.each do |user|
list[:user_list].delete user
end
end
My variable names are not the happiest choice so you can change them to improve readability.
I seem to be missing something here, but aren't you just doing this?
#task.assigned_users = User.find(params[:assigned_users_list_id])

Resources