OmniAuth ActiveRecord error when pushing to Heroku - ruby-on-rails

I'm having a strange situation occuring where I'm able to read and save information from a Facebook response via Omniauth when running locally, but when I push the exact code to Heroku the error below is coming up (from my logs) regarding the column first_name.
Processing by AdminController#index as HTML
Rendered admin/list_users.html.erb within layouts/application (60.9ms)
Completed 500 Internal Server Error in 163ms
ActionView::Template::Error (undefined method `first_name' for #<Aquarist:0x00000001ee8>):
: <td>Nickname: <%= aquarist.nickname %>
: 32: Last: <%= aquarist.last_name %></td>
: 29: <td><%= aquarist.name %></td>
: 31: First: <%= aquarist.first_name %>
: 34: <td><%= aquarist.email %></td>
: 28: <td><%= image_tag(aquarist.image, :width => '20') %></td>
: 33: <td><%= aquarist.provider %></td>
I'm using the term "aquarist" in place of user... I know this isn't standard use but for my use case it seems to make a bit more sense. I may change it back in time...
Here's my facebook callback from omniauth:
--- !ruby/hash:OmniAuth::AuthHash
provider: facebook
uid: '12456789'
info: !ruby/hash:OmniAuth::AuthHash::InfoHash
email: my#email.address.com
name: Alex
first_name: Alex
last_name: Lastname
image: http://graph.facebook.com/123456789/picture?type=square
urls: !ruby/hash:Hashie::Mash
Facebook: http://www.facebook.com/profile.php?id=12456789
credentials: !ruby/hash:Hashie::Mash
token: AACCCCb1i3ZALXEMfGxJtKZA
expires_at: 13378794564
expires: true
extra: !ruby/hash:Hashie::Mash
raw_info: !ruby/hash:Hashie::Mash
id: '12456789'
name: Alex Lastname
first_name: Alex
last_name: Lastname
link: http://www.facebook.com/profile.php?id=12456789
gender: male
email: my#email.address.com
timezone: 11
locale: en_US
verified: true
updated_time: '2012-02-01T12:51:00+0000'
As you can see I've locked down my facebook profile so don't expect to get all the extra information (eg relationship status etc).
I'm trying to build a basic profile of new users ("aquarists" in my terminology) which will pick up some of the extra information they are happy to share from facebook.
When I do this locally it works fine, I can collect my first_name, last_name, gender and locale for instance and save it to the database.
Here's the code I'm using to write the profile
def self.create_with_omniauth(auth)
create! do |aquarist|
aquarist.provider = auth["provider"]
aquarist.uid = auth["uid"]
aquarist.name = auth["info"]["name"]
aquarist.nickname = auth["info"]["nickname"]
aquarist.email = auth["info"]["email"]
aquarist.image = auth["info"]["image"]
aquarist.first_name = auth["extra"]["raw_info"]["first_name"]
aquarist.last_name = auth["extra"]["raw_info"]["last_name"]
aquarist.user_location = auth["extra"]["raw_info"]["user_location"]
aquarist.user_hometown = auth["extra"]["raw_info"]["user_hometown"]
aquarist.age = auth["extra"]["raw_info"]["age"]
aquarist.locale = auth["extra"]["raw_info"]["locale"]
aquarist.gender = auth["extra"]["raw_info"]["gender"]
end
end
I'm then using this code to display this profile information (in a table):
<% #aquarists.each do |aquarist|%>
<tr class="tbody">
<td><%= aquarist.uid %></td>
<td><%= image_tag(aquarist.image, :width => '20') %></td>
<td><%= aquarist.first_name %></td>
..and so on
The identical information when I push this code comes up with the active record error as per above.
If however I remove any of the columns from the [raw_info][extra] section the code works on Heroku (eg full name, UID, provider etc are all saved to the db).
The thing that has me completely confused is that this code is working locally - so I gather I'm requesting data from the "raw_info" section correctly.
I've already confirmed I've run my migrations on Heroku, and have - as some of other Q&As suggest - also used 'heroku restart' to ensure the database columns are being picked up in the app.
This is my OmniAuth entry in my gemfile:
gem 'omniauth'
gem 'omniauth-twitter'
gem 'omniauth-facebook'
I'm running Rails 3.1.3 and postgres 9.1.2 locally. I'm using the free Heroku database which I believe runs PG 8.x.
Here's an extract from the migration file that creates the particular columns:
def change
add_column("aquarists", "first_name", :text, :default => "")
add_column("aquarists", "last_name", :text, :default => "")
add_column("aquarists", "gender", :text, :default => "")
add_column("aquarists", "user_location", :text, :default => "")
add_column("aquarists", "user_relationships", :text, :default => "")
add_column("aquarists", "user_hometown", :text, :default => "")
add_column("aquarists", "age", :integer)
add_column("aquarists", "locale", :text, :default => "")
add_column("aquarists", "image", :text, :default => "")
add_column("aquarists", "timezone", :text, :default => "")
add_column("aquarists", "last_login", :datetime)
end
And this is what comes back when I run heroku console:
$ heroku run console
Running console attached to terminal... up, run.1
Loading production environment (Rails 3.1.3)
irb(main):001:0> Aquarist.new
=> #<Aquarist id: nil, nickname: nil, name: nil, email: nil, created_at: nil, updated_at: nil, provider: nil, uid: nil, admin: false, age: nil, locale: "", image: "", timezone: "", last_login: nil, visits: nil>
irb(main):002:0>
Any views on what may be happening when my code is hitting Heroku? Is it a Postgres version issue?

Worked out what it was ... a botched migration file. Somewhere along the line I made a (silly) modification to an original migration file, and ran it correctly in my development environment but forgot to reverse the change online.
Won't do that again, I could do with the 8 or so hours back in my life. :)

Related

How can I stop rails globalize from falling back to the fallback locale on just one field?

We use the globalize gem and have included Rails.application.config.i18n.fallbacks = [:en] in config/initializers/i18n.rb so that the user sees the English translation of a field if one does not exist in their own language.
That means we see this behavior, as expected:
class Post < ActiveRecord::Base
translates :title, :name
end
puts post.translations.inspect
# => [#<Post::Translation id: 1, post_id: 1, locale: "en", title: "Globalize rocks!", name: "Globalize">,
#<Post::Translation id: 2, post_id: 1, locale: "nl", title: '', name: nil>]
I18n.locale = :en
post.title # => 'Globalize rocks!'
post.name # => 'Globalize'
I18n.locale = :nl
post.title # => ''
post.name # => 'Globalize'
In just one place where we are displaying "posts", the client asked us to not show anything if there is no translation for the "name". Is there a built in way to do this? I.e.:
I18n.locale = :nl
post.title # => ''
post.name_if_translated # => nil
I did find one workaround:
post.name_translations[I18n.locale]
But maybe there's a better way?

ActiveRecord::Fixture::FixtureError: table "users" has no column named "monkey"

Hi I just started coding with rails, following Michael Hartl tutorial, I got this error while writing test for my app, my fixture on test/fixtures/users.yml is:
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
marwane:
name: Marwane Chahoud
email: marwane.chahoud#gmail.com
password_digest: <%= User.digest('password') %>
monkey:
name: Sterling Archer
email: sterling.archer#strange.com
password_digest: <%= User.digest('password') %>
and my db schema is: db/migrate/xxxxxx_create_users.rb :
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps null: false
end
end
end
I am using ruby version : ruby 2.2.4p230 (2015-12-16 revision 53155) [i386-mingw32]
and rails version : Rails 4.2.6
Any suggestions please ?
ActiveRecord::Fixture::FixtureError: table “users” has no column named
“monkey”
I believe its due to the indentation problem. YAML files are strict in indenting. It should be
marwane:
name: Marwane Chahoud
email: marwane.chahoud#gmail.com
password_digest: <%= User.digest('password') %>
monkey:
name: Sterling Archer
email: sterling.archer#strange.com
password_digest: <%= User.digest('password') %>
Since the key monkey: is indented wrongly, it is treated as attribute,so is the error.

Ruby on Rails - Array of Hashes - Display value based on key

I have an array of hashes saved to a Rails 5 Postgres DB (Ruby 2.3.1). I’m able to display this on my show.html.erb page like so:
<%= #item.yearly_interest_totals %>
This displays:
[
"{:financial_year=>\"2017\", :total=>\"120.08\"}",
"{:financial_year=>\"2018\", :total=>\"237.32\"}",
"{:financial_year=>\"2019\", :total=>\"163.75\"}",
"{:financial_year=>\"2020\", :total=>\"87.95\"}",
"{:financial_year=>\"2021\", :total=>\"15.38\"}"
]
Also on this page I have a variable <%= fin_year %> which displays 2017.
I’m trying to display the value corresponding to this fin_year key in the view, with the following code, but it is giving me a no implicit conversion of Symbol into Integer error…
<%= #item.yearly_interest_totals.detect do |t|
t[:financial_year] == fin_year end [:total] %>
Could somebody please explain why i'm receiving this error?
Update
Both the hash key and local variable being named the same is confusing, I have changed the local variable to fin_year.
<%= fin_year.class %> is producing String
<%= #item.yearly_interest_totals.class %> is producing Array
<%= #item.yearly_interest_totals[0][:financial_year].class %> is returning a "no implicit conversion of Symbol into Integer" error...
The problem appears to be that the values for the keys :financial_year in your array of hashes are strings (e.g. "2017"), but your value for the variable financial_year is a fixnum/integer (e.g 2017). Try making them consistent to compare, such as:
<%= #item.yearly_interest_totals.detect do |t|
t[:financial_year] == financial_year.to_s end [:total] %>
Here is output from the Rails console comparing the two:
Running via Spring preloader in process 15647
Loading development environment (Rails 4.2.7.1)
2.3.3 :001 > item_yearly_interest_totals = [{ financial_year: "2017", total: "120.08" }, { financial_year: "2018", total: "237.32" }, { financial_year: "2019", total: "163.75" }, { financial_year: "2020", total: "87.95" }, { financial_year: "2021", total: "15.38" }]
=> [{:financial_year=>"2017", :total=>"120.08"}, {:financial_year=>"2018", :total=>"237.32"}, {:financial_year=>"2019", :total=>"163.75"}, {:financial_year=>"2020", :total=>"87.95"}, {:financial_year=>"2021", :total=>"15.38"}]
2.3.3 :002 > financial_year = 2017
=> 2017
2.3.3 :003 > item_yearly_interest_totals.detect do |t|
2.3.3 :004 > t[:financial_year] == financial_year end [:total]
NoMethodError: undefined method `[]' for nil:NilClass
.
.
.
2.3.3 :005 > item_yearly_interest_totals.detect do |t|
2.3.3 :006 > t[:financial_year] == financial_year.to_s end [:total]
=> "120.08"
2.3.3 :007 >
UPDATE (02-20-2017)
I don't completely understand where the distinction within Rails lies or is occurring that is the source of your issue, but even though you execute #item.yearly_interest_totals[0].class and you get Hash, you can't seem to access the values using a hash key (e.g. [:financial_year], ["financial_year"], etc.).
After some digging, I found this:
Rails access hash value
and the accepted answer led me to try JSON.parse, which I was able to get working, albeit with .each rather than .detect. This time I did, in a Rails 5 app, create an Item model, used Postgres, and seeded a single Item. What I still did not do is create a controller or any views. I executed my code through the Rails console. So, if you duplicate my code and it does not work for you, the problem may lie there, within the controller and views.
Ultimately, there is still some discovery to be done regarding this hash/JSON distinction and how implementation leads it to manifest as one or the other.
app/models/item.rb
class Item < ApplicationRecord
validates :name, presence: true
end
db/migrate/20170220221004_enable_hstore_extension.rb
class EnableHstoreExtension < ActiveRecord::Migration
def change
enable_extension 'hstore'
end
end
db/migrate/20170220221129_create_item.rb
class CreateItem < ActiveRecord::Migration[5.0]
def change
create_table :items do |t|
t.string :name, null: false, index: { unique: true }
t.hstore :yearly_interest_totals, array: true
t.timestamps null: false
end
end
end
db/seeds.rb
Item.create(name: 'Sample Item', yearly_interest_totals: [{ financial_year: "2017", total: "120.08" }, { financial_year: "2018", total: "237.32" }, { financial_year: "2019", total: "163.75" }, { financial_year: "2020", total: "87.95" }, { financial_year: "2021", total: "15.38" }])
And here is the code as it is executed in the Rails console:
Running via Spring preloader in process 19764
Loading development environment (Rails 5.0.1)
2.4.0 :001 > #item = Item.first
Item Load (1.4ms) SELECT "items".* FROM "items" ORDER BY "items"."id" ASC LIMIT $1 [["LIMIT", 1]]
=> #<Item id: 1, name: "Sample Item", yearly_interest_totals: [{"total"=>"120.08", "financial_year"=>"2017"}, {"total"=>"237.32", "financial_year"=>"2018"}, {"total"=>"163.75", "financial_year"=>"2019"}, {"total"=>"87.95", "financial_year"=>"2020"}, {"total"=>"15.38", "financial_year"=>"2021"}], created_at: "2017-02-20 22:25:14", updated_at: "2017-02-20 22:25:14">
2.4.0 :002 > #item.class
=> Item(id: integer, name: string, yearly_interest_totals: hstore, created_at: datetime, updated_at: datetime)
2.4.0 :003 > #item.yearly_interest_totals.class
=> Array
2.4.0 :004 > #item.yearly_interest_totals[0].class
=> Hash
2.4.0 :005 > financial_year = 2017
=> 2017
2.4.0 :006 > financial_year.class
=> Integer
2.4.0 :007 > selected_year_interest_total = nil
=> nil
2.4.0 :008 > selected_year_interest_total.class
=> NilClass
2.4.0 :009 > #item.yearly_interest_totals.each do |t|
2.4.0 :010 > puts JSON.parse(t["financial_year"]).class
2.4.0 :011 > if JSON.parse(t["financial_year"]) == financial_year
2.4.0 :012?> selected_year_interest_total = JSON.parse(t["total"])
2.4.0 :013?> end
2.4.0 :014?> end
Integer
Integer
Integer
Integer
Integer
=> [{"total"=>"120.08", "financial_year"=>"2017"}, {"total"=>"237.32", "financial_year"=>"2018"}, {"total"=>"163.75", "financial_year"=>"2019"}, {"total"=>"87.95", "financial_year"=>"2020"}, {"total"=>"15.38", "financial_year"=>"2021"}]
2.4.0 :015 > selected_year_interest_total
=> 120.08
2.4.0 :016 > selected_year_interest_total.class
=> Float
I dunno about Rails 5 but maybe this will help, Rails 4, assuming that financial_year is a variable and I am understanding the question correctly:
<% #item.yearly_interest_totals.each do |t| %>
<%= t['total'] == financial_year %>
<% end %>

Creating user from rails console command?

I am newbie in Ruby, I am trying to install one app that says:
lobsters$ rails console
Loading development environment (Rails 4.1.8)
irb(main):001:0> User.create(:username => "test", :email => "test#example.com", :password => "test", :password_confirmation => "test", :is_admin => true, :is_moderator => true
irb(main):002:0> Tag.create(:tag => "test")
When I run rails console, it outputs "create some file" So how do I create user?
Try this :
User.create!(username: "test", email: "test#example.com", password: "test", password_confirmation: "test", is_admin: true, is_moderator: true)
In practice, Ruby programmers reserve ! to adorn the names of methods that do something unexpected, or perhaps a bit dangerous
So in this case, the "unexpected" result is that an exception is
raised instead of just failing and returning false.

password_digest, has_secret_password and form validations in RoR 3.1

If you haven't seen it yet, have a look at the latest railscast authentication in rails 3.1. He uses password_digest:string when generating the model and adds has_secret_password to the User model. He also adds some accessible_attributes, :password and :password_confirmation.
By using validates_confirmation_of :password we can make sure the password is confirmed before creating an instance. If I leave the password fields empty in my form I get this error message:
ruby-1.9.2-p180 :024 > u = User.new
=> #<User id: nil, name: nil, email: nil, password_digest: nil, created_at: nil, updated_at: nil>
ruby-1.9.2-p180 :027 > u.save
(0.4ms) SELECT 1 FROM "users" WHERE "users"."email" = '' LIMIT 1
=> false
ruby-1.9.2-p180 :028 > u.errors.full_messages
=> ["Password digest can't be blank"]
Of course we don't want to call the password field "Password digest" when communicating with our users. How do I change this error message?
Bonus question
When using validates_confirmation_of and using mismatching passwords I get two error messages telling me about it, and only the :password label and input tags are surrounded with fields_with_errors divs. If the passwords don't match I want to also highlight the password_confirmation input, if possible remove it altogether from the password part.
Should I write my own method for checking password confirmation? If so, could you provide some small guidelines?
The official way to solve this is to add the following to your locale file:
en:
activerecord:
attributes:
user:
password_digest: 'Password'
The English locale file is located at config/locales/en.yml. You may have to restart your server for the changes to be loaded in your environment.
To get rid of password_digest message, you can modify the view:
<% #user.errors.messages.delete(:password_digest) -%>
You could override the human_attribute_name method and set your own humanized version of the password_digest attribute. Try something like this:
HUMANIZED_ATTRIBUTES = {
:password_digest => "Password"
}
def self.human_attribute_name(attr, options={})
HUMANIZED_ATTRIBUTES[attr.to_sym] || super
end
Then your error should look like this: "Password can't be blank"

Resources