RSpec Model Validation failing but works fine in Rails Console? - ruby-on-rails

I have been really stuck on this problem. My validation for my model fails (like it should) when I'm testing it out in rails console, but my rspec example fails because it validates anyway (which it shouldn't). What am I missing here or where should I start looking?
Thanks,
Ivan
See below:
ivan:~/Development/ruby/IvanEnviromanRefinery [git:master+] → bundle exec rspec ../refinerycms-link/
.............................F.
Failures:
1) BlogPost bookmark links must have a link url if it is a link
Failure/Error: Factory.build(:post,
expected valid? to return false, got true
# /Users/ivan/Development/ruby/refinerycms-link/spec/models/blog_post_spec.rb:197:in `block (3 levels) in <top (required)>'
Finished in 6.56 seconds
31 examples, 1 failure
Failed examples:
rspec /Users/ivan/Development/ruby/refinerycms-link/spec/models/blog_post_spec.rb:196 # BlogPost bookmark links must have a link url if it is a link
ivan:~/Development/ruby/IvanEnviromanRefinery [git:master+] → rails console
Loading development environment (Rails 3.0.9)
ruby-1.9.2-p180 :001 > b = BlogPost.new
=> #<BlogPost id: nil, title: nil, body: nil, draft: nil, published_at: nil, created_at: nil, updated_at: nil, user_id: nil, cached_slug: nil, custom_url: nil, link_url: nil, is_link: nil, custom_teaser: nil>
ruby-1.9.2-p180 :002 > b.title=' 2011-06-24 8:34 '
=> " 2011-06-24 8:34 "
ruby-1.9.2-p180 :003 > b.body='goo'
=> "goo"
ruby-1.9.2-p180 :004 > b.is_link = true
=> true
ruby-1.9.2-p180 :005 > b.valid?
=> false
ruby-1.9.2-p180 :007 > b.save
=> false
ruby-1.9.2-p180 :008 > b.errors
=> {:link_url=>["must have a link_url if is_link is true"]}
ruby-1.9.2-p180 :009 >
require 'spec_helper'
Dir[File.expand_path('../../../features/support/factories/*.rb', __FILE__)].each{|factory| require factory}
describe BlogPost do
let(:blog_post ) { Factory :post }
...
describe "bookmark links" do
it "may have a bookmark link" do
Factory.build(:post,
:title => "a link",
:body => "link text",
:is_link => true,
:link_url => "http://example.com").should be_valid
end
it "must have a link url if it is a link" do
Factory.build(:post,
:title => "a link",
:body => "link text",
:is_link => true).should_not be_valid
end
end
end

Are you certain that in your second expectation the link_url isnt set somehow? Try outputting the value and check the logs
it "must have a link url if it is a link" do
post = Factory.build(:post,
:title => "a link",
:body => "link text",
:is_link => true)
Rails.logger.info "Post link: #{post.link_url}"
post.should_not be_valid
end

Related

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

Mongoid not detecting change to localized field when setting field with xxxx_translations

Gem Versions
I am using Rails 3.2.18 and Mongoid 3.1.6.
The problem
I need to set a value for any locale in a localized field, not just the one that is currently in I18n.locale. I am setting it using title_translations['en'] = 'some title', but when doing this, mongoid does not detect the change (not dirty) and so nothing is saved.
The Model
I have a mongoid model with a localized field like the following:
class ApiMethod
include Mongoid::Document
field :title, type: String, localize: true
attr_accessible :title, :title_translations
end
Console Example
Below is an example of setting the title two ways, one as title = 'xxx' and one as title_translations['en'] = 'xxx' and the result of testing if the object has changed.
2.1.2 :083 > a = ApiMethod.first
=> #<ApiMethod _id: 5541cb17fb6fc67028000006, title: {"en"=>"Dataset Catalog"}>
2.1.2 :084 > a.title
=> "Dataset Catalog"
2.1.2 :085 > a.title_translations
=> {"en"=>"Dataset Catalog"}
2.1.2 :086 > a.title = 'new title'
=> "new title"
2.1.2 :087 > a.changed?
=> true ## YEA! - THIS IS CORRECT
2.1.2 :088 > a.changed
=> ["title"]
2.1.2 :089 > a.reload
=> #<ApiMethod _id: 5541cb17fb6fc67028000006, title: {"en"=>"Dataset Catalog"}>
2.1.2 :090 > a.title_translations['en'] = 'this is a new title'
=> "this is a new title"
2.1.2 :091 > a.title
=> "this is a new title"
2.1.2 :092 > a.title_translations
=> {"en"=>"this is a new title"}
2.1.2 :093 > a.changed?
=> false ## BOO! - THIS IS NOT CORRECT
Please Help!
Am I doing something wrong or missing something? Is it not possible to set a localized field value for a locale that is not the current I18n.locale value?
Thank you for your help!
Update
I just tried something else and this works. Instead of setting the title_translations for a specific locale, I tried setting the entire title_translations object:
2.1.2 :114 > a = ApiMethod.only(:title).first
=> #<ApiMethod _id: 5541cb17fb6fc67028000006, title: {"en"=>"Dataset Catalog"}>
2.1.2 :115 > x = a.title_translations.dup
=> {"en"=>"Dataset Catalog"}
2.1.2 :116 > x['en'] = 'this is a new title'
=> "this is a new title"
2.1.2 :117 > x
=> {"en"=>"this is a new title"}
2.1.2 :118 > a.title_translations = x
=> {"en"=>"this is a new title"}
2.1.2 :119 > a.title_translations
=> {"en"=>"this is a new title"}
2.1.2 :120 > a.changed?
=> true
2.1.2 :121 > a.title_change
=> [{"en"=>"Dataset Catalog"}, {"en"=>"this is a new title"}]
So it seems like if I replace the entire value for title_translations and not just a specific locale, the change is detected. While it is nice that this works, it is not ideal. Thoughts?

Rails new objects are nil

I'm playing with rails again and found this behavior, when i create a new instance of a Post model with some attributes it tells me that all attributes are nil, why it is happening?
Loading development environment (Rails 4.0.0)
2.0.0-p451 :001 > a = Post.new(title: "Rails", content: "Rails Post")
=> #<Post id: nil, title: nil, content: nil, author: nil, rating: nil, created_at: nil, updated_at: nil>
2.0.0-p451 :002 > a.title
=> "Rails"
2.0.0-p451 :004 > a.content
=> "Rails Post"
2.0.0-p451 :005 > a.inspect
=> "#<Post id: nil, title: nil, content: nil, author: nil, rating: nil, created_at: nil, updated_at: nil>"
2.0.0-p451 :006 > a.errors.messages
=> {}
2.0.0-p451 :007 > a.valid?
=> true
class Post < ActiveRecord::Base
attr_accessor :title, :content, :author, :rating
end
You are defining attr_accessor for all your properties, which is a shortcut for defining getters and setters for an instance variable of the same name like so:
def content
#content
end
def content=(new_content)
#content = new_content
end
Rails will also auto-generate you methods with these names, for every database field that your model has. These methods will conflict with each other.
When you call post.content = 'foo', instead of calling the Rails-generated method that will internally set your model's content attribute to 'foo', you're calling the attr_accessor-defined method which will set the instance variable #content to 'foo'.
The output of inspect is iterating over the Rails-defined model attributes, not the instance variables.
Did you actually mean to declare these attributes as attr_accessible instead of attr_accessor?

protection level for model attributes in rails

Suppose the following situation
class User < ActiveRecord::Base
private
def password= p
self[:password] = p
end
def password
self[:password]
end
end
If anyone with access to the Rails console can do:
Loading development environment (Rails 4.0.0)
2.0.0p247 :001 > User
=> User(id: integer, name:string, password:string)
2.0.0p247 :002 > u = User.find(1)
=> #<User id: 1, name: "Jack", password: "da6c253ffe0975ca1ddd92865ff3d5f0">
2.0.0p247 :003 > u.password = "123"
NoMethodError: private method 'password' called for #<User:0xa9145b0>
2.0.0p247 :004 > u[:password] = "123"
=> "123"
2.0.0p247 :005 > u
=> #<User id: 1, name: "Jack", password: "123">
2.0.0p247 :005 > u.save
=> true
Why does this happen? How can I encapsulate critical fields?
I am guessing that password is attr_accessible in the model. When a field is attr_accessible, Rails automatically lets you read and write to the field. You have a private password method that overwrites the Rails password and password= methods, but you did not overwrite the [] and []= methods as well. You can either overwrite the [] and []= methods or make it so password is not attr_accessible.
Here is a code example of how to overwrite the [] method:
class User < ActiveRecord::Base
def [](word)
puts "I am the master of: #{word}"
end
def []=(key, value)
puts "Fluffy monsters"
end
end
With this revised code, here is what the [] method will return:
>> u[:password] = "123"
=> nil
# prints "Fluffy monsters" in the console
>> u[:password]
=> nil
# prints "I am the master of: password" in the console

Set date in text_field rails 3.2.1

I have just upgraded to rails 3.2.1.
I use the jQuery UI datepicker to set dates in rails text_fields. The field sets a date column in the database.
But, now it does not work.
I have this code in the view.
<%= p.text_field :due, :value => Time.now.strftime("%m/%d/%Y"), :id => "dialog_project_date" %>
If I don't change the date all goes well. If I change the date Rails puts nil in the database. This also happens when I disable jQuery datepicker and enter the date (with the right format) manually.
It seems to me that there is something with the way rails handles the formatting of the date field.
I can't find a solution. Does anybody have an idea?
Update
I used the debugger in the create action. Here's the otuput
(rdb:22) params
{"utf8"=>"✓", "authenticity_token"=>"4IChBeyKzkc4dwzje1RMPy2GBTMs5m2zrBPBFbIIKJw=", "project"=>{"name"=>"gunnaer", "description"=>"", "due"=>"03/17/2012", "customer_id"=>""}, "commit"=>"Save", "controller"=>"projects", "action"=>"create_index"}
(rdb:22) #project
#<Project id: nil, name: "gunnaer", description: "", due: nil, active: true, budget: nil, hour_price: nil, firm_id: 1, customer_id: nil, created_at: nil, updated_at: nil>
(rdb:22) #project.due = "03/17/2012"
"03/17/2012"
(rdb:22) #project
#<Project id: nil, name: "gunnaer", description: "", due: nil, active: true, budget: nil, hour_price: nil, firm_id: 1, customer_id: nil, created_at: nil, updated_at: nil>
The params is right, but the due param does not get set to the instans variable. The format is the same when I do not change the date. When I do not change it, it works.
Strange..
Your date format is wrong. Try using "yyyy/mm/dd"
This works:
ruby-1.9.2-p290 :002 > b = Blog.first
=> #<Blog id: 1, title: "Something", created_at: "2012-03-09 13:38:23", updated_at: "2012-03-09 13:38:32">
ruby-1.9.2-p290 :003 > b.created_at
=> Fri, 09 Mar 2012 13:38:23 UTC +00:00
ruby-1.9.2-p290 :004 > b.created_at = "2012/03/17"
=> "2012/03/17"
ruby-1.9.2-p290 :005 > b.save
=> true
ruby-1.9.2-p290 :006 > Blog.first
=> #<Blog id: 1, title: "Something", created_at: "2012-03-17 00:00:00", updated_at: "2012-03-09 13:58:55">
This does not:
ruby-1.9.2-p290 :007 > b.created_at = "03/17/2012"
=> "03/17/2012"
ruby-1.9.2-p290 :008 > b.save
=> true
ruby-1.9.2-p290 :009 > Blog.first
=> #<Blog id: 1, title: "Something", created_at: nil, updated_at: "2012-03-09 13:59:22">
EDIT
You have a few options for date format, which you should specify in your jquery ui code. See this link for examples - http://jqueryui.com/demos/datepicker/date-formats.html
To debug, first see what values are being POSTed to your controller. Either check the log or use a debugging proxy such as fiddle.
Then use the Rails console to isolate where the problem is happening.
UPDATED
The problem is that latest ver of Ruby (not Rails) assumes European date formats. A work-around to still use US format

Resources