bizarre ActiveRecord equality issue - ruby-on-rails

I've fixed this for my actual app fairly trivially by overriding the == operator, but it is driving me nuts and I haven't been able to find an explanation. As far as I know, ActiveRecord is supposed to determine the equality of two existing records just via the id field, right?
Apparently, no!
Loading development environment (Rails 3.0.4)
irb(main):001:0> c = ChallengeClaim.find(1)
=> #<ChallengeClaim id: 1, collection_id: 954, creation_id: nil, creation_type: nil, request_signup_id: 2, request_prompt_id: 5, claiming_user_id: 8, sent_at: nil, fulfilled_at: nil, defaulted_at: nil, created_at: "2011-09-23 04:39:07", updated_at: "2011-09-23 04:39:07">
irb(main):002:0> c2 = ChallengeClaim.find(2)
=> #<ChallengeClaim id: 2, collection_id: 954, creation_id: nil, creation_type: nil, request_signup_id: 2, request_prompt_id: 4, claiming_user_id: 8, sent_at: nil, fulfilled_at: nil, defaulted_at: nil, created_at: "2011-11-07 17:47:33", updated_at: "2011-11-07 17:47:33">
irb(main):003:0> c == c2
=> true
?!?!!??!
Any explanations gratefully welcomed so I can sleep at night again. :>

As Chris Heald pointed out above in the comments, indeed the comparison operator <=> was defined on ChallengeClaim!

Related

Spree: Return only Orders with Line Items in them

I'm having trouble setting up the controller in a spree app so it only returns orders with line_items in them.
<Spree::Order id: 1057, number: "R498797188", item_total: #<BigDecimal:7f90c2acf4b8,'0.999E1',18(18)>, total: #<BigDecimal:7f90c2acf1e8,'0.1098E1',18(18)>, state: "payment", adjustment_total: #<BigDecimal:7f90c2ace770,'0.0',9(18)>, user_id: nil, completed_at: nil, bill_address_id: 1814, ship_address_id: 1815, payment_total: #<BigDecimal:7f90c2acc358,'0.0',9(18)>, shipping_method_id: nil, shipment_state: nil, payment_state: nil, email: nil, special_instructions: nil, created_at: "2015-09-10 22:31:23", updated_at: "2015-09-10 22:33:03", currency: "USD", last_ip_address: "127.0.0.1", created_by_id: nil, shipment_total: #<BigDecimal:7f90c4b721e8,'0.199E1',18(18)>, additional_tax_total: #<BigDecimal:7f90c4b71fb8,'0.0',9(18)>, promo_total: #<BigDecimal:7f90c4b71e78,'0.0',9(18)>, channel: "spree", included_tax_total: #<BigDecimal:7f90c4b71798,'0.0',9(18)>, item_count: 1, approver_id: nil, approved_at: nil, confirmation_delivered: false, considered_risky: false>
There is a record on Spree::Order called item_count that needs to be > 0, but I don't know what the syntax needs to be in the controller?
#orders = Spree::Order.all.where(:item_count > 0) #this returns the following error: comparison of Symbol with 0 failed
This seems simple, but any help would be greatly appreciated! Thanks!
You can use symbol to check for absolute value, like where(item_count: 0), but not for comparison like that.
Inside where, when you are using symbols, you are actually working on a Hash object.
.where(item_count: 0)= .where({item_count: 0})
and to work with a hash, you should have key-value pair like above, not comparison. {:item_count > 0} is an invalid hash syntax.
For comparison in your case, use string:
#orders = Spree::Order.where('item_count > 0').all
Also, you should use .all, at the end of relation, if all needed. all returns the scope object and is usually meant to fetch all the records matching the query before it.

Create array out of data in collectioin

I have this collection
<ActiveRecord::Associations::CollectionProxy [#<Fallower user_id: 1, author_id: 2, created_at: "2015-09-06 22:59:40", updated_at: "2015-09-06 22:59:40">, #<Fallower user_id: 1, author_id: 3, created_at: "2015-09-06 22:59:40", updated_at: "2015-09-06 22:59:40">]>
and I need to create an array/collection of only "authord_id" values.
What is the best approach how to do it?
#fallowers = Fallower.where(<something>)
#authord_ids = #fallowers.map(&:authord_id)
or
#authord_ids = Fallower.where(<something>).pluck(:authord_id)
I suggest you to use collection#pluck(:author_id)
Try:
Fallower.all.collect {|f| f.author_id}
or
Fallower.pluck :author_id
also, are you sure you mean Fallower and not Follower?

Rails 4 to_json produces unexpected Exception nil is not a symbol

I am in the process of upgrading a Rails 3 application to Rails 4. In Rails 3 the json serialization of a hash containing an array of ActiveRecord objects was working correctly; now in Rails 4 it is having unpredictable results.
Here is an example object that fails with TypeError Exception: nil is not a symbol on Rails 4
{1230 =>
[
#<QuestionAnswerResponse response_id: 127, response_set_id: 6, response_group: nil, question_data_export_identifier: "is_co_pi_involved", answer: "No", question_id: 1230, answer_id: 2077, response: "">,
#<QuestionAnswerResponse response_id: 131, response_set_id: 6, response_group: nil, question_data_export_identifier: "is_co_pi_involved", answer: "No", question_id: 1230, answer_id: 2077, response: "">
]
}
Now if I take another similar object; hash containing an array of ActiveRecord objects and run to_json it works on this one...
{1234 =>
[
#<Response id: 1, response_set_id: 2, question_id: 4, answer_id: 2, datetime_value: nil, integer_value: nil, float_value: nil, unit: nil, text_value: nil, string_value: nil, response_other: nil, response_group: nil, created_at: "2014-05-30 21:17:23", updated_at: "2014-05-30 21:17:23", survey_section_id: 1, api_id: "f44b22ba-a93b-477f-8a7f-c5b4566338f0", attach_file_name: nil, attach_content_type: nil, attach_file_size: nil, attach_updated_at: nil>,
#<Response id: 2, response_set_id: 2, question_id: 10, answer_id: 10, datetime_value: nil, integer_value: nil, float_value: nil, unit: nil, text_value: "test", string_value: nil, response_other: nil, response_group: nil, created_at: "2014-05-30 21:17:23", updated_at: "2014-05-30 21:17:23", survey_section_id: 1, api_id: "e7fa8aa2-6e47-4f88-8802-949fdc902a2e", attach_file_name: nil, attach_content_type: nil, attach_file_size: nil, attach_updated_at: nil>
]
}
The view backing my QuestionAnswerResponse model does not have an id column and I was not setting a primary key in the model. In the capacity that I use this model I do not need a primary key; this is a read only view used to more easily access some complex key/value pairings directly instead of through more complex logic.
In Rails 3 this worked fine; in Rails 4 when you access a model without a primary key you end up with an attribute that looks like this in your hash nil => nil
The problem is actually up at the ActiveRecord level, but wasn't actually causing a problem until I attempt to do json serialization; at which point in time an attempt is made to call nil.to_sym which raises the exception.
This seems like a bug in ActiveRecord to me; but for now I have worked around it by manually setting a primary key on my model.

Rails where clause not equal to nil

Hey folks trying to do a simple query where I find all records where a particular attribute is nil. In this case...
irb(main):009:0> Registration.where(:registration_cancellation_token != nil)
Registration Load (0.2ms) SELECT `registrations`.* FROM `registrations` WHERE (1)
=> [#<Registration id: 1, orientation_id: 13, first_name: "mark", last_name: "Busta", email: "marklocklear#gmail.com", student_id: "3232333", phone: "3884448333", registration_cancellation_token: nil, registration_cancelled_at: nil, checked_in: false, created_at: "2014-02-20 13:46:31", updated_at: "2014-02-20 13:46:31">]
...but the query is returning all registrations. Any help appreciated...
Registration.where("registration_cancellation_token IS NOT NULL")
Registration.where.not(registration_cancellation_token: nil)
This works for Rails 4

Finding elements in array of hashes

I'm trying to build a model of products which has many components. Some components are optional and depend on the choice the user is making to enable them or not.
I have two models, one is configuration and the other is elements (of that configuration).
At the beginning I bring all the elements of the array, and then create another array of those which will be shown by default.
But when I write the following code it gives me an error despite both objects being arrays of hashes.
So I bring my first array of all elements:
irb(main):252:0* #all = Configuration.find(1).elements
=> [#<Element id: 1, name: "elem1", quantity: 1, position: 1, subposition: nil, created_at: nil, updated_at: nil, configuration_id: 1>, #<Element id: 2, name: "elem2", quantity: 2, position: 2, subposition: 1, created_at: nil, updated_at: nil, configuration_id: 1>, #<Element id: 3, name: "elem3", quantity: 3, position: 2, subposition: 2, created_at: nil, updated_at: nil, configuration_id: 1>, #<Element id: 4, name: "elem4", quantity: 4, position: 3, subposition: nil, created_at: nil, updated_at: nil, configuration_id: 1>]
Then I filter to be only those that have a subposition nil or 1
irb(main):253:0> #default = #all.where(:subposition=>nil).concat(#all.where(:subposition=>1))
=> [#<Element id: 1, name: "elem1", quantity: 1, position: 1, subposition: nil, created_at: nil, updated_at: nil, configuration_id: 1>, #<Element id: 4, name: "elem4", quantity: 4, position: 3, subposition: nil, created_at: nil, updated_at: nil, configuration_id: 1>, #<Element id: 2, name: "elem2", quantity: 2, position: 2, subposition: 1, created_at: nil, updated_at: nil, configuration_id: 1>]
So far so good, as you can see, Elem3 is not being shown in #default as it doesn't meet the requiements.
The problem comes when I try to play with the arrays as I need to perform certain operations.
irb(main):257:0> #all.where(:position =>1)
=> [#<Element id: 1, name: "elem1", quantity: 1, position: 1, subposition: nil, created_at: nil, updated_at: nil, configuration_id: 1>]
But the same operation in #default will fail,
irb(main):258:0> #default.where(:position =>1)
NoMethodError: undefined method `where' for #<Array:0x2641660>
Now, they're both arrays of hashes and look the same, why is the same method failing in the second case?
Thanks a lot for your help!
Throughout your code, #all is an ActiveRecord::Relation, not an array. This lets you perform the standard .where call (among others). When you assigned to #default, you used .concat which evaluated the query and assigned an actual array to #default.
You might try a different approach in your second code block. Maybe something like this:
#default = #all.where("subposition is null or subposition = ?", 1)
Well, your problem is that concat transforms a collection into an array.
I'd replace:
irb(main):253:0> #default = #all.where(:subposition=>nil).concat(#all.where(:subposition=>1))
by:
#default = #all.where("subposition = '1' OR subposition = nil") #I'm unsure of the nil in the statement, I nerver remember, try NULL if it fails
This way, you make only one db query and you keep an ActiveRecord collection.
Thus, you'll be able to chain other where conditions on it.

Resources