Is ActiveRecord lying? - ruby-on-rails

My ActiveRecord is not telling the truth. See for yourself:
> User.posts.class
=> Array
> User.posts.all.class
=> Array
> a = Array.new
> a.class
=> Array
> a.all
NoMethodError: undefined method `all' for []:Array
There is no Array#all method, so User.posts can't be an Array. What is going on here?

this is the way that associations are implemented in rails. they are lazy proxy objects.
have a look at the documentation for further infos on this: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/collection_proxy.rb#L25

Ruby has a notion of singleton methods. This means that objects can change the behaviour defined by their class. Read this.

Related

undefined method `last' for #<Hash:0x00007f303593d6d8>

trying the below code in a custom sdk in Workato
poll: lambda do |connection, input, last_updated_at|
per_page = 1
last_updated_at = (last_updated_at || input['since']).to_time.utc.iso8601
candidates = get("https://api.stripe.com/v1/customers")
last_updated_at = candidates.last["created"] unless candidates.blank?
Getting an error
undefined method `last' for #Hash:0x00007f303593d6d8 at line:
There is no Hash#last method. Hashes do keep their insertion order, but you should conceptually treat them as unordered. The concept of the "last" element of a Hash simply does not make sense.

Why can't I access this value in an (OpenStruct) object?

I have an (OpenStruct) object for which I can only seem to access some values. A simplified version of it is below:
#<Project::API::FormData::FormAnswer:0x007f94de911ed0
#form_answer=
#<OpenStruct
user_id=130,
timer_value=[{"foo" => "bar"}]
>
>
If I want to get user_id, that's easy
> answer.user_id
130
But what about timer_value?
> answer.timer_value
NoMethodError: undefined method `timer_value' for #<Project::API::FormData::FormAnswer:0x007f94de911ed0>
> answer.timer_value
NoMethodError: undefined method `timer_value' for #<Project::API::FormData::FormAnswer:0x007f94de911ed0>
maybe, for some reason, for this I need to access it through the form_answer first:
> answer.form_answer.timer_value
NoMethodError: undefined method `form_answer' for #<Project::API::FormData::FormAnswer:0x007f94de911ed0>
---
> answer.first.timer_value
NoMethodError: undefined method `first' for #<Project::API::FormData::FormAnswer:0x007f94de911ed0>
I'm not experienced with OpenStruct - is this the cause?
I have an (OpenStruct) object
No, you don't. You seem to have a PORO* that has a field/instance_variable of type OpenStruct. And given the fact that answer.user_id works, you likely have something like this in that class:
delegate :user_id, to: :#form_answer
That is, FormAnswer class re-exports a property of one of its internal fields. But does not re-export timer_value, for example. Nor does it expose #form_answer.
* plain old ruby object
Thanks Sergio, I found that just as you posted - is indeed an issue in where the class is defined - which I thought that I'd read through, but as ever read and read again. It seems whomever created the class left a bug monkeying up the method definitions:
fields.each do |field_name|
define_method(field_name) { #form_answer.public_send(field_name) }
end
Which is all good, but the fields array was malformed meaning only some values were coming through.
> answer.respond_to?(:timer_value)
true
Bingo!

lambda select map difference in rails 4

Servernode is Rails Model Class.
I found something strange to me when I try to use lambda.
aaa = lambda {|node| node.available="Available"}
Servernode.select(&:aaa)
=> It can return array of ModelObject which meets the condition
But, when I try to
bbb = lambda {|node| node if node.available="Available"}
Servernode.map(&:bbb)
NoMethodError: undefined method `map' for #<Class:0x000000067759b0>
The result is not what I expected and don't know why?
Thanks for help!
This is because select is an ActiveRecord::QueryObject method. I think you've confused it with the select method for Ruby Enumerable. The map method is only available for enumerables as well.

Rails 3 - NoMethodError: undefined method for nil:NilClass in each Iteration

I'm iterating over an array of instances of a Rails model. Here is my code:
product_details.each do |product_detail|
product_detail.label = Backend::ProductGroup.where(product_group_number: product_detail.product_group).first.label
end
The attribute 'label' from 'product_detail' isn't an attribute from my Rails ActiveRecord model. I added it with attr_accessor in my class definition. I did this, because I wanted to add this attribute dynamically, only when I need to do this. When I ran the code without the 'each' iteration in my rails console it works just fine. But when I execute the above code I get the following error message:
NoMethodError: undefined method 'label' for nil:NilClass
Did I do something obviously wrong?
Many thanks in advance.
You likely have several product_detail items that have no matching product_group. So calling .first on the empty collection returns nil. To get around the error, you can test if the product_group was found before proceeding:
product_details.each do |product_detail|
product_group = Backend::ProductGroup.where(product_group_number: product_detail.product_group).first
product_detail.label = product_group.label if product_group
end
You can also do this more efficiently like so:
group_labels = BackEnd::ProductGroup.
where(product_group_number: product_details.map(&:product_group)).
inject({}){|m, g| m[g.product_group_number] = g.label; m}
product_details.each do |product_detail|
product_detail.label = group_labels[product_detail.product_group]
end
This will result in a single database call to grab all related groups, and put the labels in a keyed hash for easy discovery and assignment.

Cannot access data in active record using dot notation

I created a model in Ruby and am stuck on a n00b issue. In Rails Console:
s = Survey.where(:keyword => 'foo')
=> [#]
s.inittxtmsg
NoMethodError: undefined method inittxtmsg' for #<ActiveRecord::Relation:0x10350f8f8>
from /Library/Ruby/Gems/1.8/gems/activerecord-3.0.5/lib/active_record/relation.rb:371:inmethod_missing'
from (irb):3
Shouldn't I be able to see the values by typing s.Survey_id, s.inittxtmsg, s.keyword, s.store?
Thank you!
Survey.where(:keyword => 'foo')
returns an array of results, so you are really calling .inittxtmsg on an array, which obviously doesn't exist.
You could do something like:
Survey.where(:keyword => 'foo').first.inittxtmsg, in which it is calling it on the actual model object.
Or if you know that there is only one survey with the keyword = foo... you can use the find method to only return a single model object:
s = Survery.find_by_keyword("foo")
s.inittxtmsg

Resources