Attributes of an Object - ruby-on-rails

There is function of attributes_name in Active record by which I can check the keys of an object but I can check the blank keys for of an object which is of MongoID not of ActiveRecord,
When I try this I got the following response
ruby-1.9.2-p290 :001 > u = User.new
=> #<User _id: 4e684f7771393161cc000001, _type: nil, username: nil, first_name: nil, last_name: nil, email: nil, password: nil, password_salt: nil, password_hash: nil, profile_picture: nil, facebook_id: nil, facebook_enabled: nil, facebook_access_token: nil, twitter_id: nil, twitter_enabled: nil, twitter_access_token: nil, twitter_access_secret: nil, points: nil, remember_token: nil, remember_token_expires_at: nil, active: false, activation_code: nil, activated_at: nil>
ruby-1.9.2-p290 :002 > u.attributes.keys
=> ["active", "_id"]
It only show the attributes which are not nill , How can I check all the attributes even which are nil ?
I actually wanted to make function which needs to use user.attributes.keys.include?('name')

Probably you want fields. Attributes is more or less related to what you got from db, fields is what you defined in your model. Following works for me:
User.fields.keys
User.first.fields.keys

User.attributes.keys
worked with me but you can try columns
User.columns.map(&:name)

To get the keys in the same order as the columns in the db I used this on Rails 3.2 Ruby 1.8.7:
User.content_columns.collect{|c| c.send(:name)}
my particular use was achieved from a variable with an array of objects
#objects.first.class.content_columns.collect{|c| c.send(:name)}

Related

merge 2 array of hashes based on different keys in rails

I have 2 query results one of them is an array of hashes like this
[{"user_id"=>"1", "latlng"=>[#<BigDecimal:7fc67f8412d0,'0.43653226E2',18(36)>, #<BigDecimal:7fc67f840560,'-0.793831843E2',18(36)>], "loc"=>["Toronto", "Ontario", "Canada"]}, {"user_id"=>"2", "latlng"=>[#<BigDecimal:7fc67f84a8f8,'0.43653226E2',18(36)>, #<BigDecimal:7fc67f849d18,'-0.793831843E2',18(36)>], "loc"=>["Toronto", "Ontario", "Canada"]}, {"user_id"=>"3", "latlng"=>[#<BigDecimal:7fc67f848828,'0.43653226E2',18(36)>, #<BigDecimal:7fc67f848210,'-0.793831843E2',18(36)>], "loc"=>["Toronto", "Ontario", "Canada"]}, {"user_id"=>"4", "latlng"=>[#<BigDecimal:7fc67f852620,'0.43653226E2',18(36)>, #<BigDecimal:7fc67f851b30,'-0.793831843E2',18(36)>], "loc"=>["Toronto", "Ontario", "Canada"]}, {"user_id"=>"5", "latlng"=>[#<BigDecimal:7fc67f85ae88,'0.43653226E2',18(36)>, #<BigDecimal:7fc67f85a9b0,'-0.793831843E2',18(36)>], "loc"=>["Toronto", "Ontario", "Canada"]}]
the second is an active record relations object of users,
<ActiveRecord::Relation [#<User id: 4, email: "hello.misc#gmail.com", username: "steve", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 13, current_sign_in_at: "2017-02-18 21:16:17", last_sign_in_at: "2017-01-14 20:32:57", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", confirmed_at: "2016-12-13 01:42:57", confirmation_sent_at: "2016-12-13 01:42:55", unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, created_at: "2016-12-13 01:42:55", updated_at: "2017-02-18 22:03:46", slug: "user2", uuid: "xdn5n5z3fmr4", impressions_count: 1, likers_count: 3, lat: #<BigDecimal:7fc67fc39130,'0.0',9(27)>, lng: #<BigDecimal:7fc67fc38c30,'0.0',9(27)>, currently_online: false, status: "unverified", deleted_at: nil>, #<User id: 5, email: "jack#gmail.com", username: "user21", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2017-02-17 02:49:07", last_sign_in_at: "2017-02-17 02:49:07", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", confirmed_at: "2017-02-17 02:49:10", confirmation_sent_at: "2017-02-17 02:49:07", unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, created_at: "2017-02-17 02:49:07", updated_at: "2017-02-17 02:49:43", slug: "user21", uuid: "xtffdh2ajnp7", impressions_count: 1, likers_count: 0, lat: #<BigDecimal:7fc67fca6758,'0.0',9(27)>, lng: #<BigDecimal:7fc67fca5ec0,'0.0',9(27)>, currently_online: false, status: "unverified", deleted_at: nil>]>
What I want to do, is to merge the first array of hashes into the activerecord relations based on the foreign key of the first array,
so if the first array has an user_id of 3, i want to insert that hash into that active record of the user with an ID of 3 on the active record object.
I came up up with this
index = a1.group_by{|entry| entry["id"]}
i2= a2.map{|entry| (index[entry.id] || []).reduce(entry, :merge) }
but its not merging them together at all.. what am I doing wrong?
edit: Not all of the first array is relevent, I only want to selectively get the item from the first array based on whats returned in the active record collection of the second query
edit2: I am not looking to save the data back, I just want to merge the data set to display it back in a view template.
If you use Array#map or collect on the collection, you're going to end up with an array instead of an ActiveRecord collection, which may not be what you want.
You could add virtual attributes to the User model and then iterate over the collection:
# app/models/user.rb
attr_accessor :latlon, :loc
users.each do |user|
if location = location_array[user.id.to_s]
user.latlon = location['latlng']
user.loc = location['loc']
end
end
This probably won't be very efficient, but for a small paginated dataset it might not be a big deal.
Another option would be to use a decorator pattern, which acts like a wrapper around your user object. In this case you would add your location attributes to the decorator rather than injecting them into the collection. Have a look at the Draper gem for a good overview.
If I understood you correctly, you can do something like this:
# users is an array of ActiveRecord::Relation
# extra_data is the hash
users.each do |user|
# .detect basically will return an object (first appearance) or nil
data = extra_data.detect{|d| d["user_id"].to_i == user.id}
if data.present?
user.lat = data["latlng"][0]
user.lng = data["latlng"][1]
# if you want to attach "loc", add a attr_accesor :loc in your Use model
# user.loc = data["loc"]
end
end
If you want to know more about detect method, read the docs.

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 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 update individual attribute not working

I have the following scenario:
A user cancels their account, and optionally gives a reason.
The reason is saved, and the user is soft_deleted.
For some reason my code to set the reason doesn't result in any updates being saved.
Here is my code:
class User < ActiveRecord::Base
def set_cancellation_reason(reason)
cancellation_reason = reason
save!
end
end
What is wrong here that cancellation_reason is not getting persisted?
This is what happens if I run the code from the console:
u = User.first
User Load (2.0ms) SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL ORDER BY "users"."id" ASC LIMIT 1
=> #<User id: 1, email: "leebrooks0#gmail.com", encrypted_password: "$2a$15$GQ.WHk.nxlArc668bf3NW.WFJVV.ost3R85PGs6ePYaT...", role_id: nil, reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 11, current_sign_in_at: "2014-03-21 12:08:54", last_sign_in_at: "2014-03-21 12:06:31", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", confirmation_token: nil, confirmed_at: "2014-03-21 10:59:27", confirmation_sent_at: nil, unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, cancellation_reason: nil, created_at: "2014-03-21 10:59:27", updated_at: "2014-03-21 12:12:29", deleted_at: nil>
2.1.1 :008 > u.set_cancellation_reason("hogwash")
(0.5ms) BEGIN
(0.4ms) COMMIT
=> true
I might nbe missing something on how it is being called, but I would do the following. I am assuming this is being called from a controller or view.
Called by using myuser.set_cancellation_reason("don't like it")
def set_cancellation_reason(reason)
self.cancellation_reason = reason
self.save!
end
I'm also assuming you set the cancelled flag somewheer else otheriwse you need
self.cancel_flag = true
When doing cancellation_reason = reason, it will create a cancellation_reason variable instead of calling the dynamic method cancellation_reason= defined by Active Record.
self is the default receiver but when the expression can be ambiguously considered to be an assignation, the assignation wins.
You can use self.cancellation_reason = reason to be sure to pick up the rails method but I prefer doing the following :
update_attribute(:cancellation_reason, reason)
I think it's more clear, and you don't need an extra line for saving.

Ruby on Rails: more verbose tests

This test keeps failing and I don't know why:
test "correctly formatted profile_name2" do
user = User.new(first_name: 'Jim', last_name: 'Johnson', email: 'jim#teamtreehouse.com', password: 'awfawwf', profile_name: "jimmy")
puts user.errors.inspect
assert user.valid?
end
I tried to find out by that puts user.errors.inspect statement, but I get back an array (I think) that simply lists database input rather than precisely what's failing.
For clarification:
<ActiveModel::Errors:0x00000103c8ad30 #base=#<User id: nil, first_name: "Jim", last_name: "Johnson", profile_name: "jimmy", email: "jim#teamtreehouse.com", encrypted_password: "$2a$04$LTOb5O.gG0DEITsb/HDOb.fPLP83LaXzKlEerwCDE1og...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, authentication_token: nil, created_at: nil, updated_at: nil>, #messages={}>
In future tests, what statements are used in tests to print to screen explicitly what's going wrong?
Instead of outputting more verbose information within your tests, it might also help to set the TESTOPTS argument to get verbose output when you run your tests.
For example you would set it like this:
rake test TESTOPTS="-v"

Resources