Mongoid update_attributes not persisting - ruby-on-rails

I'm running an update_attributes command to add two new added fields in one of my user documents in my rails console and it says true on the command being ran, but nothing is persisting in the database.
User.last (simplified):
#<User _id: 4c77d555b1382g539f000022, first_name: "Jason", last_name: "Johnson">
Commands I tried running (following the http://mongoid.org docs):
User.last.update_attributes(nickname: 'Josh', email: 'josh#gmail.com')
User.last.update_attribute(:nickname, 'Josh') # I get a NoMethodError: undefined method `update_attribute'
user.rb
field :first_name
field :last_name
field :nickname # just added this
field :email # just added this
mongoid gem version:
rails (3.0.3)
mongoid (2.0.0.beta.20)

I suspect that you had an empty users collection when you got the NoMethodError.
The following works for Rails 3.2.3, Mongoid 2.4.10.
I suggest copying and running the test so that you have a known environment for each thing that you are testing.
class User
include Mongoid::Document
field :first_name
field :last_name
field :nickname
field :email
end
test/unit/user_test.rb
require 'test_helper'
class UserTest < ActiveSupport::TestCase
def setup
User.delete_all
end
test "update_attribute" do
User.create(first_name: 'Jason', last_name: 'Johnson')
assert_equal(1, User.count)
p User.last
User.last.update_attribute(:nickname, 'Josh')
p User.last
User.last.update_attributes(nickname: 'Josh', email: 'josh#gmail.com')
p User.last
end
end
test output
Run options: --name=test_update_attribute
# Running tests:
#<User _id: 4fc63ff5e4d30b08ca000001, _type: nil, first_name: "Jason", last_name: "Johnson", nickname: nil, email: nil>
#<User _id: 4fc63ff5e4d30b08ca000001, _type: nil, first_name: "Jason", last_name: "Johnson", nickname: "Josh", email: nil>
#<User _id: 4fc63ff5e4d30b08ca000001, _type: nil, first_name: "Jason", last_name: "Johnson", nickname: "Josh", email: "josh#gmail.com">
.
Finished tests in 0.019296s, 51.8242 tests/s, 51.8242 assertions/s.

Related

RSpec controller GET #index test is returning an empty ActiveRecord array instead of my model

Please excuse my rustiness, first time touching Rails and this project in quite some time.
Ruby Version: 2.5.0
Rails Version: 5.1.7
RSpec Version: 3.9.3
FactoryBot Version: 6.2.0
This is my scripts_controller_spec.rb file with model creation and the test in question:
require 'rails_helper'
describe ScriptsController, type: :controller do
userID_1 = User.create!(
email: 'ueferfrfrf#u1.com',
password: 'useruser',
password_confirmation: 'useruser'
)
script1 = Script.create!(
name: 'YWoodcutter',
skill: 'Woodcutting',
bot_for: 'TRiBot',
game_for: 'Oldschool Runescape 07',
user_id: userID_1.id
)
script1.save
describe "GET #index" do
it "assigns #scripts" do
get :index
p script1
expect(assigns(:scripts)).to eq([script1])
end
end
When running the tests, the print line above outputs this, as expected:
#<Script id: 1, name: "YWoodcutter", skill: "Woodcutting", bot_for: "TRiBot", game_for: "Oldschool Runescape 07", user_id: 1, created_at:
"2021-10-19 08:29:43", updated_at: "2021-10-19 08:29:43">
However, I get this test failure:
Failures:
ScriptsController GET #index assigns #scripts
Failure/Error: expect(assigns(:scripts)).to eq([script1])
expected: [#<Script id: 1, name: "YWoodcutter", skill: "Woodcutting", bot_for: "TRiBot", game_for: "Oldschool Runescape 07",
user_id: 1, created_at: "2021-10-19 08:29:43", updated_at: "2021-10-19
08:29:43">]
 
got: #<ActiveRecord::Relation []>
(compared using ==)
My scripts_controller.rb index function looks like so:
class ScriptsController < ApplicationController
def index
#scripts = Script.order(:created_at)
end
Let me know if you need any more info, and thanks for your help!
I think the Script object is not getting created before calling the index action. Because of this, you are getting the empty ActiveRecord::Relation. In this situation let! should fix your problem
require 'rails_helper'
describe ScriptsController, type: :controller do
let!(:user_1) do
User.create!(
email: 'ueferfrfrf#u1.com',
password: 'useruser',
password_confirmation: 'useruser'
)
end
let!(:script1) do
Script.create!(
name: 'YWoodcutter',
skill: 'Woodcutting',
bot_for: 'TRiBot',
game_for: 'Oldschool Runescape 07',
user_id: user_1.id
)
end
describe "GET #index" do
before { get :index }
it "assigns #scripts" do
expect(assigns(:scripts)).to eq([script1])
end
end
end
Based on the current code, it seems you were not calling all script.
Using
### Controller
#scripts = Script.all.order(:created_at)
### Test
## Should use factories to create the records
let(:user) do
create(:user, email: 'ueferfrfrf#u1.com',
password: 'useruser',
password_confirmation: 'useruser')
end
let(:script) do
create(:script, name: 'YWoodcutter',
skill: 'Woodcutting',
bot_for: 'TRiBot',
game_for: 'Oldschool Runescape 07',
user: user)
end
should fix it.

Rails 5 field _type not generated in mongoid

I have class & subclass with one document looks like :
class Core::User
include Mongoid::Document
include Mongoid::Timestamps
store_in collection: 'users'
end
class Core::Moderator < Core::User
end
I tried to add a user from console
2.4.2 :002 > user = Core::User.new(email: 'email#domain.com', name: 'new user')
=> #<Core::User _id: BSON::ObjectId('5a015465fe37a86430b1e0ff'), created_at: nil, email: "email#domain.com", name: "new_user", updated_at: nil>
2.4.2 :003 > user.save
=> true
2.4.2 :004 > user._type
NoMethodError: undefined method `_type' for #<Core::User:0x0000000003e77ea0>
from (irb):4
And then add new moderator :
2.4.2 :005 > moderator = Core::Moderator.new(email: 'email2#domail.com', name: 'new moderator')
#<Core::Moderator _id: BSON::ObjectId('5a015600fe37a86430b1e100'), created_at: nil, email: "email2#domain.com", name: "new moderator", updated_at: nil>
2.4.2 :006 > moderator.save
=> true
2.4.2 :007 > moderator._type
=> "Core::Moderator"
Next add new user again :
2.4.2 :008 > user = Core::User.new(email: 'email3#domain.com', name: 'new user 2')
=> #<Core::User _id: BSON::ObjectId('5a015704fe37a86430b1e101'), created_at: nil, email: "email3#domain.com", name: "new user 2", updated_at: nil>
2.4.2 :009 > user.save
=> true
2.4.2 :010 > user._type
=> "Core::User"
Why I should create subclass first to get field _type on parent class? Every I start new console and create new user (Core::User) the field _type not generated.
I user Ruby 2.4.2, Rails 5.1.4, Mongoid 6.2.1
In order for inheritance to work as expected in Mongoid you need to set preload_models: true. Otherwise the model cannot know that it has subclasses.
# config/mongoid.yml
development:
# ...
options:
# ...
# Preload all models in development, needed when models use
# inheritance. (default: false)
preload_models: true

FactoryGirl + Faker - same data being generated for every object in db seed data

I am using FactoryGirl and Faker to generate user objects in my seeds.rb file but for some reason the exact same user is being created and rake db:seed is failing because of an email uniqueness validation.
Factory for users:
#users.rb
require 'faker'
FactoryGirl.define do
factory :user do
first_name Faker::Name.first_name
last_name Faker::Name.last_name
phone Faker::PhoneNumber.cell_phone
email Faker::Internet.email
password "password"
password_confirmation "password"
end
end
And the code in seeds.rb file:
#seeds.rb
rand(5..11).times { FactoryGirl.create(:user) }
Error:
ActiveRecord::RecordInvalid: Validation failed: Email has already been taken
If I open the console and use FactoryGirl.create(:user) I get the same results...same object is being created over and over even though if I run just Faker::Internet.email several times I'll get several e-mails.
FactoryGirl:
[1] pry(main)> FactoryGirl.create(:user)
...
=> #<User id: 3, first_name: "Osvaldo", last_name: "Wunsch", email: "willy#damore.net", phone: "(912)530-4949 x64848", created_at: "2014-07-31 20:57:27", updated_at: "2014-07-31 20:57:27", encrypted_password: "$2a$10$mxWC7yLYR0m/Sw8MO6Lyru.xuTHCdCEuM9Orx3LXGApF...", 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>
[2] pry(main)> FactoryGirl.create(:user)
...
ActiveRecord::RecordInvalid: Validation failed: Email has already been taken
Faker by itself:
[3] pry(main)> Faker::Internet.email
=> "hobart_purdy#goodwinmills.org"
[4] pry(main)> Faker::Internet.email
=> "pierce_brekke#gislasonrolfson.net"
What am I missing here? Why is Faker producing the same data every time when used through FactoryGirl?
You need to pass a block if you want the values re-evaluated for each instance created.
Instead of
email Faker::Internet.email
try...
email { Faker::Internet.email }
Using Faker to get uniqueness-passing attributes may be an anti-pattern. It may also be a bad idea to have Faker's semi-random output in tests - what if sometimes tests just fail and you are off to a wild goose chase just because Faker coughed up a value you did not expect?
Lately I have been using FactoryGirl's sequences to get predictable, yet uniqueness-passing values.
FactoryGirl.define do
factory :user do
sequence(:first_name, 1) { |n| "John#{n}" }
sequence(:last_name, 1) { |n| "Doe#{n}" }
sequence(:phone, 1) { |n| (111111111+n).to_s }
sequence(:email, 1) { |n| "email#{n}#example.com" }
password "password"
password_confirmation "password"
end
end
FactoryGirl.create(:user).email #=> "email1#example.com"
FactoryGirl.create(:user).email #=> "email2#example.com"
Taken from Factory Girl tips # http://arjanvandergaag.nl/blog/factory_girl_tips.html

Ruby validation passes in console, fails in rake task

This is my EmailContact model:
class EmailContact < ActiveRecord::Base
validates :email, :presence => true, :email => true
end
I am using the ruby gem valid_email.
I run the following in my rails console, in the same environment as my rake task I will show later:
>> email_contact = EmailContact.new(:email => 'a253545#gmail.com')
>> email_contact.valid?
true
So, as you can see, in the rails console I am building an EmailContact and it is valid.
Then I run this in my rake task:
list_entity = {:branch=>"Nashua Branch-YMCA of Greater Nashua", :branch_id=>"485", :call_type=>nil, :client_id=>"2264", :client_name=>"YMCA of Greater Nashua", :date_of_birth=>nil, :email=>"a253545#gmail.com", :first_name=>"Sridhar", :last_name=>"Tipirneni", :list_entity_id=>"277795", :mem_id=>"4085008", :mem_unit_id=>"2138728", :member_id=>"0213262-01", :membership_type=>"Dual 2 Adult Family", :membership_type_id=>"5203", :most_recent_join_date=>nil, :old_membership_type=>nil, :phone_number=>"(970)456-1010", :primary_language=>"English", :termination_date=>nil, :termination_reason=>nil, :unit_id=>"0213262", :unit_type=>nil, :visits=>nil, :"#i:type"=>"c:NpsListEntityDto"}
email_contact = EmailContact.new(list_entity.except(:"#i:type"))
puts email_contact.valid?
This returns false. The only validation, at all, is the email. Why does this email validate successfully in my console but fail in my rake task?
FYI, when I remove :email => true from my EmailContact model and only validate the presence of an :email, they both work fine. So the issue is definitely within the :email => true piece of my validation, but I don't understand why it passes in one place and fails in another.
EDIT
In my console, my model looks like this when using the full list_entity:
#<EmailContact id: nil, branch: "Nashua Branch-YMCA of Greater Nashua", branch_id: 485, call_type: nil, client_id: 2264, client_name: "YMCA of Greater Nashua", date_of_birth: nil, email: "a253545#gmail.com", first_name: "Sridhar", last_name: "Tipirneni", list_entity_id: 277795, mem_id: "4085008", mem_unit_id: "2138728", member_id: "0213262-01", membership_type: "Dual 2 Adult Family", membership_type_id: 5203, most_recent_join_date: nil, old_membership_type: nil, phone_number: "(970)456-1010", primary_language: "English", termination_date: nil, termination_reason: nil, unit_id: "0213262", visits: nil, loaded_at: nil, failed_at: nil, unit_type: nil, created_at: nil, updated_at: nil, list_id: nil>
In my rake task, when I run email_contact.inspect, this is returned:
#<EmailContact id: nil, branch: "Nashua Branch-YMCA of Greater Nashua", branch_id: 485, call_type: nil, client_id: 2264, client_name: "YMCA of Greater Nashua", date_of_birth: nil, email: "a253545#gmail.com", first_name: "Sridhar", last_name: "Tipirneni", list_entity_id: 277795, mem_id: "4085008", mem_unit_id: "2138728", member_id: "0213262-01", membership_type: "Dual 2 Adult Family", membership_type_id: 5203, most_recent_join_date: nil, old_membership_type: nil, phone_number: "(970)456-1010", primary_language: "English", termination_date: nil, termination_reason: nil, unit_id: "0213262", visits: nil, loaded_at: nil, failed_at: nil, unit_type: nil, created_at: nil, updated_at: nil, list_id: nil>
As you can see, they are both the exact same - The console model is valid, the rake model is invalid.
EDIT 2
I am using the valid_email gem, mentioned above. Here is the filepath:
/Users/luigi/.rvm/gems/ruby-2.0.0-p247#hub/gems/valid_email-0.0.4/lib/valid_email/email_validator.rb
All of my other gems are stored here as well it seems like.
It may also be worth mentioning that I get this warning before the validation fails:
[deprecated] I18n.enforce_available_locales will default to true in
the future. If you really want to skip validation of your locale you
can set I18n.enforce_available_locales = false to avoid this message.
20 hours later, I found the issue.
Using savon, all of the strings returned in my hash were being converted to a datatype of Nori::StringWithAttributes. The encoding was the same (UTF-8), but the class was different.
Running email_contact.email = email_contact.email.to_s prior to checking if the model is valid solves the issue.

Rails Syntax for entering data in sqlite

I have been following this tutorial, http://ruby.railstutorial.org/chapters/modeling-users?version=3.2#top,
and I tried this in the rails console
User.new(name: "Michael Hartl", email: "mhart#example.com")
SyntaxError: compile error
but when I tried this it worked:
User.new(:name=> "Michael Hartl", :email=>"mhart#example.com")
=> #<User id: nil, name: "Michael Hartl", email: "mhart#example.com", created_at: nil, updated_at: nil>
I am using rails 3.2.1, which I guess this is the problem, but why change the syntax to something more complicated like, :<variable>=> instead of <variable>: ??
You didn't type it correctly.
User.new(name: "Michael Hartl", email: "mhart#example.com")

Resources