Rails model logic giving wrong result - ruby-on-rails

When i do some logic on a colum value after copied to some variable, my actual colum value on the object is getting changed, my model methods are,
def copy_configuration_values
element_positions_dup = element_positions.dup
cert_element.read_attribute(:field_names)["configuration_values"].each { |k, v|
element_positions_dup["configuration_values"][k] = v if configuration_value_present?(k)
}
element_positions_dup
end
def configuration_value_present?(configuration)
element_positions["configuration_values"] && element_positions["configuration_values"][configuration]
end
And when i call this method from console like below,
1.9.3p194 :001 > t = CertTemplate.find 30
CertTemplate Load (0.3ms) SELECT `cert_templates`.* FROM `cert_templates` WHERE `cert_templates`.`id` = 30 LIMIT 1
=> #<CertTemplate id: 30, name: "aaaaaaaaaaaq", cert_element_id: 22, element_positions: {"configuration_values"=>{"Program"=>"9.523810492621529,24.627720154437824"}, "custom_fields"=>{"college"=>"22.64550296843998,15.349369638973906", "code"=>"16.790123349144345,15.463920671915272"}, "custom_fields_for_rows"=>{"subject name"=>"30.68783230251736,16.609393247624034"}}, created_at: "2012-08-08 07:18:33", updated_at: "2012-08-16 08:03:52", image_file_name: "Marksheet_Updated.jpg", image_content_type: "image/jpeg", image_file_size: 2236497, image_updated_at: "2012-08-08 07:18:33">
1.9.3p194 :002 >
1.9.3p194 :003 > t.copy_configuration_values
CertElement Load (0.2ms) SELECT `cert_elements`.* FROM `cert_elements` WHERE `cert_elements`.`id` = 22 LIMIT 1
=> {"configuration_values"=>{"Program"=>"2"}, "custom_fields"=>{"college"=>"22.64550296843998,15.349369638973906", "code"=>"16.790123349144345,15.463920671915272"}, "custom_fields_for_rows"=>{"subject name"=>"30.68783230251736,16.609393247624034"}}
1.9.3p194 :004 >
1.9.3p194 :005 > t
=> #<CertTemplate id: 30, name: "aaaaaaaaaaaq", cert_element_id: 22, element_positions: {"configuration_values"=>{"Program"=>"2"}, "custom_fields"=>{"college"=>"22.64550296843998,15.349369638973906", "code"=>"16.790123349144345,15.463920671915272"}, "custom_fields_for_rows"=>{"subject name"=>"30.68783230251736,16.609393247624034"}}, created_at: "2012-08-08 07:18:33", updated_at: "2012-08-16 08:03:52", image_file_name: "Marksheet_Updated.jpg", image_content_type: "image/jpeg", image_file_size: 2236497, image_updated_at: "2012-08-08 07:18:33">
1.9.3p194 :006 >
My actual column value is getting changed, what i am doing wrong. Advance thanks.

It looks like the problem is you are assigning references to nested hashes when you iterate through the key values, instead of copies.
Like specifically, "custom_fields" key in both element_positions and element_positions_dup will point to the same Hash object as the value because you assign it without duplicating it. To fix it try
...
element_positions_dup["configuration_values"][k] = v.dup if configuration_value_present?(k)
...
Edit: yeah you need deep copies
Use Marshal serialization

Related

Rails - how to fetch from ActiveRecord object only specific records?

I get this from an ActiveRecord call:
#<ActiveRecord::Associations::CollectionProxy [
#<CarService id: nil, car_id: nil, car_service: 1,
created_at: nil, updated_at: nil, car_type: 0>,
#<CarService id: nil, car_id: nil, car_service: 11,
created_at: nil, updated_at: nil, car_type: 1>]>
Once I get this, I need to filter only records where car_type = "0". How to do that without doing another database call (WHERE car_type = "0")?
Thank you in advance.
EDIT:
this:
car.car_services.select{|key, hash| hash['car_type'] == "1" }
does not work.
just convert your result to an array then filter it like this
result = car.car_services.to_a.select do |e|
e.car_type == "0"
end
You can use scope in CarService model:
scope :type_ones, -> { where(car_type: 1) }
and you can use it like this:
car.car_services.type_ones
If you use enum, it will be better. Because the enum creates to scopes automatically instead of you. And of course it has more features. More about the enum.

Rails ActiveRecord .where method doesn't execute SQL query

I've written a set of Rails search methods that takes an optional parameter to define the rigor of the search. The core method is as follows:
class Participant < ActiveRecord::Base
def self.matches(field_name, param, rigor = 'exact')
where("lower(#{field_name}) like ?", "#{param}") if rigor == 'exact'
where("lower(#{field_name}) like ?", "%#{param}%") if rigor == 'soft'
end
end
I'm getting this result:
[1] pry(main)> >> Participant.matches('last_name', 'Goodman', 'soft')
Participant.matches('last_name', 'Goodman', 'soft')
Participant Load (5.1ms) SELECT "participants".* FROM "participants" WHERE (lower(last_name) like '%Goodman%')
=> [#<Participant:0x007fc6fecee8d0
id: 17,
first_name: "Harris",
last_name: "Goodman",
gender: 0,
birthdate: nil,
city: nil,
state_code: "CA",
email: nil,
phone: nil,
created_at: Wed, 30 Mar 2016 11:18:33 MDT -06:00,
updated_at: Wed, 30 Mar 2016 11:18:33 MDT -06:00,
created_by: 1,
updated_by: 1,
country_code: "US",
user_id: nil>]
[2] pry(main)> >> Participant.matches('last_name', 'Goodman', 'exact')
Participant.matches('last_name', 'Goodman', 'exact')
=> nil
Rails doesn't seem to be firing the SQL query when the 'exact' parameter is passed.
I've also tried = in place of like but get the same result. Worked on this for over an hour with no success. Any ideas would be welcome.
EDIT: OK, so a bit of refactoring solves the problem:
def self.matches(field_name, param)
where("lower(#{field_name}) like ?", "%#{param}%")
end
def self.exact_matches(field_name, param)
where("lower(#{field_name}) like ?", "#{param}")
end
I would still like to know why this works but the more elegant earlier solution does not.
Every function/method returns the last evaluated value.
In your case it's
where("lower(#{field_name}) like ?", "%#{param}%") if rigor == 'soft'
which returns nil if rigor is not 'soft'.
So adding a return should doing what you want:
def self.matches(field_name, param, rigor = 'exact')
return where("lower(#{field_name}) like ?", "#{param}") if rigor == 'exact'
where("lower(#{field_name}) like ?", "%#{param}%") if rigor == 'soft'
end

select all the values of the records belonging to a specific field of the database and save them in a array Active Record

I have the following set of records . I want to save in a array called #texts only
the values of the field text doing an each o a for
1.9.3-p547 :074 > Tweet.all
Tweet Load (0.3ms) SELECT "tweets".* FROM "tweets"
=> [#<Tweet id: 1, text: "hola a todos", zombie_id: 5, created_at: "2014-12-29 23:52:40", updated_at: "2014-12-29 23:52:40">, #<Tweet id: 2, text: "hola como estas", zombie_id: 5, created_at: "2014-12-30 00:09:40", updated_at: "2014-12-30 00:09:40">, #<Tweet id: 3, text: "hello", zombie_id: 5, created_at: "2014-12-30 12:44:41", updated_at: "2014-12-30 12:44:41">]
1.9.3-p547 :075 >
Example
#texts=["hola a todos","hola cmo estas", "hello"];
I would do this:
#texts = Tweet.all.map(&:text)
Or:
#texts = Tweet.pluck(:text)
You should use pluck, as for the documentation:
Use pluck as a shortcut to select one or more attributes without
loading a bunch of records just to grab the attributes you want.
This way you are only select the desired columns and not the "full" record.

Ruby's nil? function not working

I am using Ruby 1.9.3.
This is what is happening in the console:
1.9.3-p392 :028 > p = Product.find(1)
Product Load (0.4ms) SELECT `products`.* FROM `products` WHERE `products`.`id` = 1 LIMIT 1
=> #<Product id: 1, name: "Product 4", image: nil, available: true>
1.9.3-p392 :029 > p.image
=>
1.9.3-p392 :030 > p.image.nil?
=> false
When the product is returned, the image is obviously nil, but when I try and get the value (p.image) it does not show anything.
Why is the p.image.nil? command not returning true?
Use .blank? it'll return true if the attribute is nil or empty

Group by part of attribute in hash

I have a model called coverage that looks like this
1.9.3p429 :005 > Coverage.new
=> #<Coverage id: nil, postcode: nil, name: nil, created_at: nil, updated_at: nil>
Here is an example record:
1.9.3p429 :006 > Coverage.find(10)
Coverage Load (7.3ms) SELECT "coverages".* FROM "coverages" WHERE "coverages"."id" = $1 LIMIT 1 [["id", 10]]
=> #<Coverage id: 10, postcode: "N10", name: "N10 - Muswell Hill", created_at: "2013-05-22 14:42:37", updated_at: "2013-05-22 14:42:37">
I've got over 300 postcodes and I want to group them by some values I have in this array
group = ['N','E','EC','LS','TS']
So I would like to do
#postcodes = Coverage.all
run it through something with the above array to get the following hash
#postcode_hash = { 'N' => [ '#Active Record for N1', '#Active Record for N2' ], 'E' => [ '#Active Record for E1', '#Active Record for E2' ] }
# note: not complete should contain all index from the above array
You can use the .group_by{} method:
#postcodes = Coverage.all
#postcodes_hash = #postcodes.group_by{ |c| c.postcode.gsub(/[0-9]/, '') }
Take a look at the group_by documentation:
http://apidock.com/rails/Enumerable/group_by
There is the explicit version of above:
#postcode_hash = {}
group = ['N','E','EC','LS','TS']
group.each{ |code| #postcode_hash[code] = [] }
#postcodes = Coverage.scoped # similar to .all but better
#postcodes.map do |coverage|
code = coverage.postcode.gsub(/[0-9]/, '') # takes off all the numbers of the postcode
#postcode_hash[code] << coverage if #postcode_hash[code]
end

Resources