Ruby on Rails: more verbose tests - ruby-on-rails

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"

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.

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 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 - how to parse this object

I am making a call to a REST API and I get back a bunch of values. I am trying to figure out how to parse them.
Here are the values:
#<User _id: 4f8de8c40a5dcd0d1d00004c, agency_requested: [], encrypted_password: "$2a$10$FPVJDLkkD6AXd5SY/hL6KeuC6QR6vfU3OKI3oGCPxrTiEnAwvGOOu", avatar_file_size: nil, avatar_file_name: nil, agreed_to_terms: ["v1"], location: nil, last_name_first_initial: "Genadinik, A.", first_initial_last_name: "A. Genadinik", legacy_blogger_id: nil, created_at: Tue Apr 17 22:03:50 UTC 2012, active_advertiser_id: nil, avatar_source: :default, agency_roles: [], last_sign_in_ip: "127.0.0.1", confirmation_sent_at: Tue Apr 17 22:03:50 UTC 2012, created_via: "CMPLY-WEB", deleted_at: nil, updated_at: Fri May 11 16:37:16 UTC 2012, last_sign_in_at: Thu May 10 20:48:53 UTC 2012, display_welcome_help: true, program_influencers: [], agency_rep: true, account_type: :influencer, legacy_user_id: nil, sign_in_count: 44, _type: nil, avatar_content_type: nil, programs: [], active_agency_id: nil, account_status: :active, admin_roles: [], legacy_password: nil, gets_newsletter: false, full_name: "Alex Genadinik", last_name: "Genadinik", reset_password_token: nil, current_sign_in_ip: "127.0.0.1", authentication_token: "ViQ5q89n39zyyVUT3wLp", user_name: "me_n0_like_scrennames", time_zone: "Chihuahua", bio: nil, reset_password_sent_at: nil, current_sign_in_at: Fri May 11 16:37:16 UTC 2012, confirmation_token: nil, avatar_updated_at: nil, last_name_first_name: "Genadinik, Alex", agency_id: nil, first_name: "Alex", confirmed_at: Tue Apr 17 22:49:28 UTC 2012, email: "alex#cmp.ly">
How would a parser look like? I am pretty new to Ruby and the stuff returned is kind of difficult to make sense of, so I am not certain how/where to start.
So far I have something like:
begin
// But not sure how to loop through this stuff and extract the values.
end
rescue Exception => ex
# Do something
end
Thanks in advance for the suggestions.
In a rails app, once you have the JSON, you can just do:
decoded_json = ActiveSupport::JSON.decode(json)
decoded_json will be a hash, and you can access the values using the keys from the json, for example:
decoded_json["_id"]
decoded_json["location"]
You could also consider using something like HTTParty to deal with your communications with the RESTful API, as described here:
http://mike.bailey.net.au/2011/02/json-with-ruby-and-rails/

Attributes of an Object

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)}

Resources