this works:
ids = [1,2]
varietals = Varietal.find(:all, :conditions => [ "id IN (?)",ids])
But what I want to do is that plus have a condition of: deleted => false
varietals = Varietal.find(:all, :conditions =>{ :deleted => false})
any ideas?
am i going to have to use find_by_sql?
I would handle this with a named_scope to communicate intent and foster re-use:
named_scope :undeleted,
:conditions => { :deleted => false }
Then you can simply use:
varietals = Varietal.undeleted.find([1,2])
You can do it a few ways, but this is the most straight forward:
varietals = Varietal.find( [1,2], :conditions => { :deleted => false })
You can see in the docs that the first parameter of find can take an integer or an array.
ids = [1,2]
varietals = Varietal.find(:all, :conditions => {:id => ids, :deleted => false})
This should work, haven't tested it though.
From the docs:
An array may be used in the hash to
use the SQL IN operator:
Student.find(:all, :conditions => { :grade => [9,11,12] })
Related
I am using rails 2.3. In my application it uses
val = Party.find(:all, :conditions => [" type in ('Physician') || id in (?)",PartyLabel.find(:all,:conditions=>"label_id=#{Label.find_by_label("Can Schedule").id}").collect{|p| p.party_id if Party.find(p.party_id).respond_to?("provider_organizations")}], :with_disabled => true).select{|physician| not physician.provider_organizations.blank? }.collect{|enum| [enum.display_name_schedule, enum.id]}
code to achieve some requirements. Now i wants to split the code in to 2 parts.
1. phys = Physician.find(:all, :include => :provider_organizations, :with_disabled => true).select{|physician| not physician.provider_organizations.blank? }.collect{|enum| [enum.display_name_schedule, enum.id]}
it's working fine.. and the second part will be
2. sch = Party.find(:all, :include => [:as_labels], :conditions => {:label => {:label => "Can Schedule"}}.respond_to?("provider_organizations")).select{|physician| not physician.provider_organizations.blank? }.collect{|enum| [enum.display_name_schedule, enum.id]}
it shows NoMethodError (undefined method 'provider_organizations' for #<ProviderOrganization:0x1ab81c20>): error message... Any comments could be appreciated..
It looks like respond_to?("provider_organizations") is called for a wrong object. Here is your code #2:
sch = Party.find(
:all,
:include => [:as_labels],
:conditions => {
:label => {
:label => "Can Schedule"
}
}.respond_to?("provider_organizations") # What's this ???
).select{ |physician|
not physician.provider_organizations.blank?
}.collect{ |enum|
[enum.display_name_schedule, enum.id]
}
If I understand it correctly, the respond_to? should be inside the select:
...
).select{ |physician|
physician.respond_to?("provider_organizations") && not physician.provider_organizations.blank?
}.collect{ ...
I have totally nine buttons in rails. I have input the data into the database by manually typing the #button_1.save function.
My question is:
How can i have the #button_i.save function in rails? I have finished the things in the for loop, what is left is the button save functions.
Many thanks!
button_number = params[:button_number]
for i in (1..button_number)
instance_variable_set("#button#{i}",
Button.new(:title => params["button_title_#{i}".to_sym],
:order => i,
:icon_url => params["button_icon_#{i}".to_sym],
:navigation_id => #navigation.id,
:next_navigation => params["selected_navigation_#{i}".to_sym].to_i,
:next_page => params["selected_page_#{i}".to_sym].to_i))
instance_variable_set("#button#{i}")
end
#button1.save
#button2.save
#button3.save
#button4.save
#button5.save
#button6.save
for i in ...
eval("#button#{i}.save")
end
The opposite of instance_variable_set is instance_variable_get, which I think will lead you to the correct answer:
1.upto(params[:button_number].to_i) do |i|
instance_variable_set("#button#{i}",
Button.new(
:title => params["button_title_#{i}".to_sym],
:order => i,
:icon_url => params["button_icon_#{i}".to_sym],
:navigation_id => #navigation.id,
:next_navigation => params["selected_navigation_#{i}".to_sym].to_i,
:next_page => params["selected_page_#{i}".to_sym].to_i
)
)
instance_variable_get("#button#{i}").save
end
Try by using constantize ruby function because I think your function call statement is in string.
button_number = params[:button_number]
for i in (1..button_number)
instance_variable_set("#button#{i}",
Button.new(:title => params["button_title_#{i}".to_sym],
:order => i,
:icon_url => params["button_icon_#{i}".to_sym],
:navigation_id => #navigation.id,
:next_navigation => params["selected_navigation_#{i}".to_sym].to_i,
:next_page => params["selected_page_#{i}".to_sym].to_i))
"#button#{i}".constantize.save();
end
May be this that you want -
button_number = params[:button_number].to_i
for i in (1..button_number)
instance_variable_set("#button#{i}",
Button.new(:title => params["button_title_#{i}".to_sym],
:order => i,
:icon_url => params["button_icon_#{i}".to_sym],
:navigation_id => #navigation.id,
:next_navigation => params["selected_navigation_#{i}".to_sym].to_i,
:next_page => params["selected_page_#{i}".to_sym].to_i))
instance_variable_set("#button#{i}")
"#button#{i}".save
end
baza_managers = BazaManager.find(:all,
:conditions => ["or_unit_id != ?", 1]).collect {
|mou| [mou.email, mou.or_unit_id]}
respondent_emails = Respondent.find(:all).collect {|r| r.email }
ERROR:
from lib/scripts/baza_sync.rb:26:in `each'
from lib/scripts/baza_sync.rb:26
26 line ↓
baza_managers.each do |moi|
if !respondent_emails.include?(moi)
Respondent.create(:email => moi, :user_id => 1, :respondent_group_id => moi)
end
end
ERROR I GET:
undefined method `email' for ["vadasd#test.test.com", 8]:Array (NoMethodError)
I don't know why I'm getting this error.
try with:
baza_managers = BazaManager.find(:all,
:conditions => ["or_unit_id != ?", 1]).collect {
|mou| [mou.email, mou.or_unit_id]}
respondent_emails = Respondent.find(:all).collect {|r| r.email }
baza_managers.each do |moi|
if !respondent_emails.include?(moi[0])
Respondent.create(:email => moi[0], :user_id => 1, :respondent_group_id => moi[1])
end
end
Fix your code with following:
if !respondent_emails.include?(moi[0])
Respondent.create(:email => moi[0], :user_id => 1, :respondent_group_id => moi[1])
end
I would think there is at least one error not in the way you are using collect but in the logic you write on the last lines when you go through the baza_managers array.
With this code the condition respondent_emails.include?(moi) will be always false because respondent_emails is an array of email addresses but moi is an array like ["vadasd#test.test.com", 8] so they will never match.
I think this mistake made you make an error in the line :
Respondent.create(:email => moi, :user_id => 1, :respondent_group_id => moi)
Because this line will be evaluate as (for example) :
Respondent.create(:email => ["vadasd#test.test.com", 8], :user_id => 1, :respondent_group_id => ["vadasd#test.test.com", 8])
Which is probably not what you want.
Last, I would suggest you to read the debugger rails guide, I often use debugger to figure out where and what is the problem in this kind of code and error.
I would rewrite your code as follows:
baza_managers = BazaManager.all(:conditions => ["or_unit_id != ?", 1]).
collect { |mou| [mou.email, mou.or_unit_id]}
respondent_emails = Respondent.find(:all).collect {|r| r.email }
baza_managers.each do |email, unit_id|
unless respondent_emails.include?(email)
Respondent.create(:email => email, :user_id => 1,
:respondent_group_id => unit_id)
end
end
This solution can be further optimized by using OUTER JOIN to detect missing Respondents
BazaManager.all(
:include => "OUTER JOIN respondents A ON baza_managers.email = A.email",
:conditions => ["baza_managers.or_unit_id != ? AND A.id IS NULL", 1]
).each do |bm|
Respondent.create(:email => bm.email, :respondent_group_id => bm.or_unit_id,
:user_id => 1)
end
The solution can be made elegant and optimal by adding associations and named_scope.
class BazaManager
has_many :respondents, :foreign_key => :email, :primary_key => :email
named_scope :without_respondents, :include => :respondents,
:conditions =>["baza_managers.or_unit_id != ? AND respondents.id IS NULL", 1]
end
Now the named_scope can be used as follows:
BazaManager.without_respondents.each do |bm|
Respondent.create(:email => bm.email, :respondent_group_id => bm.or_unit_id,
:user_id => 1)
end
a[0] = {:id => '1234', :value => '37'}
a[1] = {:id => '4321', :value => '50'}
a[2] = {:id => '1122', :value => '50'}
From here I want to be able to check to see if a hash exists with :id => '4321' without having to loop through the array manually. Is there anything where I can do something like this: a.exists?(:id => '4321') ? I've tried a few things but can't seem to figure it out. Thanks!
How about:
a.any? {|x| x[:id] == '4321' }
That will return true if the block returns true.
I have a bunch of named scopes and have a method within one of them that I would like to share between the other named scopes. I've sort of accomplished this by using define_method and a lambda. However, there is still some repeated code and I'm wondering is there a better approach?
Here's a simplified example of what I've got. Assume I have a table of projects and each project has many users.
Within the User model I have...
filter_by_name = lambda { |name| detect {|user| user.name == name} }
named_scope :active, :conditions => {:active => true} do
define_method :filter_by_name, filter_by_name
end
named_scope :inactive, :conditions => {:active => false} do
define_method :filter_by_name, filter_by_name
end
named_scope :have_logged_in, :conditions => {:logged_in => true} do
define_method :filter_by_name, filter_by_name
end
Then I would use it like...
active_users = Project.find(1).users.active
some_users = active_users.filter_by_name ["Pete", "Alan"]
other_users = active_users.filter_by_name "Rob"
logged_in_users = Project.find(1).users.logged_in
more_users = logged_in_users.filter_by_name "John"
Here's an entirely different solution that is probably more in spirit with what the question was asking for.
named_scope takes a block, which could be any Proc. So if you create a lambda/Proc which defines the filter_by_name method, you can pass it as the last argument to a named_scope.
filter_by_name = lambda { |name| detect {|user| user.name == name} }
add_filter_by_name = lambda { define_method :filter_by_name, filter_by_name }
named_scope(:active, :conditions => {:active => true}, &add_filter_by_name)
named_scope(:inactive, :conditions => {:active => false}, &add_filter_by_name)
named_scope(:have_logged_in, :conditions => {:logged_in => true}, &add_filter_by_name)
This will do what you're looking for. If you still think it's too repetitive, you can combine it with the techniques in mrjake2's solution to define many named scopes at once. Something like this:
method_params = {
:active => { :active => true },
:inactive => { :active => false },
:have_logged_in => { :logged_in => true }
}
filter_by_name = lambda { |name| detect {|user| user.name == name} }
add_filter_by_name = lambda { define_method :filter_by_name, filter_by_name }
method_params.keys.each do |method_name|
send(:named_scope method_name, :conditions => method_params[method_name],
&add_filter_by_name)
end
Named scopes can be chained, so you're making this harder on your self than you need to.
The following when defined in the user model will get you what you want:
class User < ActiveRecord::Base
...
named_scope :filter_by_name, lambda { |name|
{:conditions => { :name => name} }
}
named_scope :active, :conditions => {:active => true}
named_scope :inactive, :conditions => {:active => false}
named_scope :have_logged_in, :conditions => {:logged_in => true}
end
Then the following snippets will work:
active_users = Project.find(1).users.active
some_users = active_users.filter_by_name( ["Pete", "Alan"]
other_users = active_users.filter_by_name "Rob"
logged_in_users = Project.find(1).users.have_logged_in
more_users = logged_in_users.filter_by_name "John"
I see that you're using detect, probably to avoid excess hits to the DB. But your examples don't use it properly. Detect only returns the first element in a list that the block returns true for. In the above example, some_users will only be a single record, the first user that is named either "Pete" or "Alan". If you're looking to get all users named "Pete" or "Alan" then you want select. And if you want select then you're better off using a named scope.
Named scopes when evaluated return a special object that contains the components necessary to build the SQL statement to generate the results, chaining other named scopes still doesn't execute the statement. Not until you try to access methods on the result set, such as calling each or map.
I would probably use a bit of metaprogramming:
method_params = {
:active => { :active => true },
:inactive => { :active => false },
:have_logged_in => { :logged_in => true }
}
method_params.keys.each do |method_name|
send :named_scope method_name, :conditions => method_params[method_name] do
define_method :filter_by_name, filter_by_name
end
end
This way if you wanted to add more finders in the future, you could just add the method name and conditions to the methods_param hash.
You can also do this with a second named scope.
named_scope :active, :conditions => {:active => true}
named_scope :inactive, :conditions => {:active => false}
named_scope :have_logged_in, :conditions => {:logged_in => true}
named_scope :filter_by_name, lambda {|name| :conditions => ["first_name = ? OR last_name = ?", name, name]}
Then you can do #project.users.active.filter_by_name('Francis').
If you really need to do this with Enumerable#detect, I would define the filter_by_name method in a module which can then extend the named scopes:
with_options(:extend => FilterUsersByName) do |fubn|
fubn.named_scope :active, :conditions => {:active => true}
fubn.named_scope :inactive, :conditions => {:active => false}
fubn.named_scope :have_logged_in, :conditions => {:logged_in => true}
end
module FilterUsersByName
def filter_by_name(name)
detect {|user| user.name == name}
end
end
This adds the filter_by_name method to the class returned by all three named scopes.