allow_nil: false does not work from rails console - ruby-on-rails

Newbie here, trying to add some rules to a ruby on rails form, specifically I don't want to allow the creation of an item if this has not a name
class Idea < ActiveRecord::Base
mount_uploader :picture, PictureUploader
belongs_to :project
validates :name, presence: true, allow_nil: false
end
Works smoothly if I create a new item from my app, but not happens the same if I create one item from rails console. How can I avoid the creation of an item without name, no matter if this has been created in the app or in the rails console?

The problem is you have to set allow_blank: false instead of allow_nil: false.
In Ruby an empty string is not nil.
"".nil?
#=> false
"".blank?
#=> true
Update your model like this
class Idea < ActiveRecord::Base
mount_uploader :picture, PictureUploader
belongs_to :project
validates :name, presence: true, allow_blank: false
end
If you want know the differences between nil and blank,see this SO post.
Refer these Guides for allow_blank

Try this from console:-
Idea.create(:name => "Something")
Rails console output:-
1.9.3-p385 :005 > c = CabinNumber.create(:name => "Something")
(0.2ms) begin transaction
SQL (1.1ms) INSERT INTO "cabin_numbers" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Sun, 25 May 2014 00:02:04 IST +05:30], ["name", "Something"], ["status", false], ["updated_at", Sun, 25 May 2014 00:02:04 IST +05:30]]
(139.6ms) commit transaction
=> #<CabinNumber id: 11, name: "Something", status: false, created_at: "2014-05-24 18:32:04", updated_at: "2014-05-24 18:32:04">
OR
idea = Idea.new(:name => "hello")
idea.save
Rails console output:-
1.9.3-p385 :007 > c = CabinNumber.new(:name => "hello")
=> #<CabinNumber id: nil, name: "hello", status: false, created_at: nil, updated_at: nil>
1.9.3-p385 :008 > c.save
(0.1ms) begin transaction
SQL (1.0ms) INSERT INTO "cabin_numbers" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Sun, 25 May 2014 00:02:57 IST +05:30], ["name", "hello"], ["status", false], ["updated_at", Sun, 25 May 2014 00:02:57 IST +05:30]]
(155.0ms) commit transaction
=> true
Cannot create if name field is not provided
1.9.3-p385 :003 > c = CabinNumber.create()
(0.2ms) begin transaction
(0.1ms) rollback transaction
=> #<CabinNumber id: nil, name: nil, status: false, created_at: nil, updated_at: nil>

Related

Rails simple model attributes not saved to database

I am developing a small Rails 3 app that reads data from the Steam API. What I am seeing is that the model attributes for any ActiveRecord model I create are not saved to the database nor are they output if I debug them.
Here my sample model
class NonPlayableApp < ActiveRecord::Base
attr_accessor :name, :steam_id
attr_accessible :name, :steam_id
end
With the migration file being:
class CreateNonPlayableApps < ActiveRecord::Migration
def change
create_table :non_playable_apps do |t|
t.string :name
t.string :steam_id
t.timestamps
end
end
end
Here are few tests with the Rails console, I get the same results when I try them in a controller and inspect or yaml the model:
irb(main):001:0> temp = NonPlayableApp.new( steam_id: 33333, name: "Testing" )
=> #<NonPlayableApp id: nil, name: nil, steam_id: nil, created_at: nil, updated_at: nil>
irb(main):002:0> temp.steam_id
=> 33333
irb(main):003:0> temp.name
=> "Testing"
irb(main):004:0> temp.save
(0.1ms) begin transaction
SQL (4.0ms) INSERT INTO "non_playable_apps" ("created_at", "name", "steam_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Fri, 26 Feb 2016 19:40:37 UTC +00:00], ["name", nil], ["steam_id", nil], ["updated_at", Fri, 26 Feb 2016 19:40:37 UTC +00:00]]
(8.8ms) commit transaction
=> true
irb(main):005:0> temp.steam_id
=> 33333
irb(main):006:0> temp
=> #<NonPlayableApp id: 64, name: nil, steam_id: nil, created_at: "2016-02-26 19:40:37", updated_at: "2016-02-26 19:40:37">
irb(main):007:0> temp2 = NonPlayableApp.first
NonPlayableApp Load (1.6ms) SELECT "non_playable_apps".* FROM "non_playable_apps" LIMIT 1
=> #<NonPlayableApp id: 64, name: nil, steam_id: nil, created_at: "2016-02-26 19:40:37", updated_at: "2016-02-26 19:40:37">
irb(main):008:0> temp2.steam_id
=> nil
irb(main):009:0> temp2.name
=> nil
What am I missing?
attr_accessor :name, :steam_id overrides the setter and getter methods that Rails automatically generates for that attributes.
Just delete the attr_accessor :name, :steam_id line from your model.

MultiSelect Not Passing Multiple Values

I have a application that allows a user to upload a creative and assign it to multiple weeks
Week Model
class Week < ActiveRecord::Base
has_many :creative_weeks
has_many :creatives, :through => :creative_weeks
end
Creative Model
class Creative < ActiveRecord::Base
has_many :creative_weeks
has_many :weeks, :through => :creative_weeks
mount_uploader :image, CreativeUploader
end
Creative Weeks [Join Table]
class CreativeWeek < ActiveRecord::Base
belongs_to :week
belongs_to :creative
end
I know the association works which allows me to issue a creative to multiple weeks based on my console:
2.0.0p353 :020 > c = Creative.first
Creative Load (0.2ms) SELECT "creatives".* FROM "creatives" ORDER BY "creatives"."id" ASC LIMIT 1
=> #<Creative id: 10, name: "", account_id: 1, week_id: nil, campaign_id: 1, image: "Quakes_2013_DigiOOH_40YR_704x496.jpg", created_at: "2014-02-20 18:13:47", u
pdated_at: "2014-02-20 18:13:47">
2.0.0p353 :021 > c.week_ids
(0.2ms) SELECT "weeks".id FROM "weeks" INNER JOIN "creative_weeks" ON "weeks"."id" = "creative_weeks"."week_id" WHERE "creative_weeks"."creative_id" = ? [["
creative_id", 10]]
=> [3]
2.0.0p353 :022 > c.week_ids = [1, 2, 3]
Week Load (0.2ms) SELECT "weeks".* FROM "weeks" WHERE "weeks"."id" IN (1, 2, 3)
Week Load (0.1ms) SELECT "weeks".* FROM "weeks" INNER JOIN "creative_weeks" ON "weeks"."id" = "creative_weeks"."week_id" WHERE "creative_weeks"."creative_id"
= ? [["creative_id", 10]]
(0.1ms) begin transaction
SQL (0.3ms) INSERT INTO "creative_weeks" ("created_at", "creative_id", "updated_at", "week_id") VALUES (?, ?, ?, ?) [["created_at", Thu, 20 Feb 2014 18:20:27
UTC +00:00], ["creative_id", 10], ["updated_at", Thu, 20 Feb 2014 18:20:27 UTC +00:00], ["week_id", 1]]
SQL (0.1ms) INSERT INTO "creative_weeks" ("created_at", "creative_id", "updated_at", "week_id") VALUES (?, ?, ?, ?) [["created_at", Thu, 20 Feb 2014 18:20:27
UTC +00:00], ["creative_id", 10], ["updated_at", Thu, 20 Feb 2014 18:20:27 UTC +00:00], ["week_id", 2]]
(1.0ms) commit transaction
=> [1, 2, 3]
2.0.0p353 :023 >
The issue I am having is getting this same functionality to work on the front end. It will only pass in one value, typically the last one chosen
In my form:
<div class="field">
<%= f.collection_select(:week_ids, Week.all, :id, :start_at, {}, multiple: true, name: 'creative[week_ids]') %>
</div>
Can anyone advise me what I am missing?
TIA
Change the select tag's name to this:
name: 'creative[week_ids][]'
That extra '[]' at the end of the name specifies that you want an array of values to be posted.
Using strong parameters you have to specify that the value will be an array:
def your_strong_params
params.require(:creative).permit(week_ids: [])
end

Rails console outputs dirty/outdated data

I'm following Michael's Ruby on Rails tutorial (Chapter 6.2.2) and when I go to the rails console --sandbox to attempt to create Users the outputs come totally outdated.
I update a user's attribute, I return the user and the console outputs nil for all attributes. However if I output the user.attribute the data is there.
The first save fails because a user must have a name, though I had this problem even before addind validations.
What am I missing here? I followed all the instructions and I'm doing pretty basic stuff. I'm executing the following commands:
$ rails console --sandbox
Loading development environment in sandbox (Rails 4.0.2)
Any modifications you make will be rolled back on exit
2.1.0 :001 > user = User.new(name: "", email: "mhartl#example.com")
=> #<User id: nil, name: nil, email: nil, citizen_number: nil, created_at: nil, updated_at: nil>
2.1.0 :002 > user.save
(0.1ms) SAVEPOINT active_record_1
(0.2ms) ROLLBACK TO SAVEPOINT active_record_1
=> false
2.1.0 :003 > user.valid?
=> false
2.1.0 :004 > user.name = "Bob"
=> "Bob"
2.1.0 :005 > user.valid?
=> true
2.1.0 :006 > user
=> #<User id: nil, name: nil, email: nil, citizen_number: nil, created_at: nil, updated_at: nil>
2.1.0 :007 > user.save
(0.2ms) SAVEPOINT active_record_1
SQL (6.2ms) INSERT INTO "users" ("created_at", "updated_at") VALUES (?, ?) [["created_at", Sat, 08 Feb 2014 19:15:37 UTC +00:00], ["updated_at", Sat, 08 Feb 2014 19:15:37 UTC +00:00]]
(0.1ms) RELEASE SAVEPOINT active_record_1
=> true
2.1.0 :008 > user
=> #<User id: 1, name: nil, email: nil, citizen_number: nil, created_at: "2014-02-08 19:15:37", updated_at: "2014-02-08 19:15:37">
My user model:
class User < ActiveRecord::Base
attr_accessor :name, :email, :citizen_number
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
VALID_CITIZEN_NUMBER_REGEX = /[1-9]\d{7,}/
validates :name, presence: true, length: { maximum: 50 }
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
validates :citizen_number, presence: true, format: { with: VALID_CITIZEN_NUMBER_REGEX }, uniqueness: true
before_save { lowercase_email() }
def lowercase_email()
self.email = email.downcase
end
end
DiAlex, do you have the code that produced this? I'd like to try it. Since the issue is actually something that happens before the save but after "initialization", I can't see how reload or the validations matter.
Update: Based on the tests and back and forth with you, I think your problem is related with the misuse of attr_accessor and attr_accessible.
Try removing :citizen_number from the attr_accessor. I tried that and your code started working (passing all your tests) and the console started outputting the correct values too.
Use reload
user.reload should give your up to date user with the correct attributes, as explained in the Documentation, it reloads the attributes of this object from the database, so you can now get the object attributes as expected, if they saved correctly
Diogo, something is preventing your user.save. After the first attempt of user.save, try user.errors. This will give you a hash with the errors that prevented your model to save.
Most probably you will find an error in your DB Scheme, as the user.valid? returns true.
Have you tried without sandbox mode? Perhaps it is somehow restricting the write.
rails console

Strange ActiveRecord model behavior

I have model
class Owner < ActiveRecord::Base
attr_accessible :telephone
validates_uniqueness_of :telephone
validates_telephone_number_of :telephone
before_validation :telephone_normalize
end
in rails console
a = Owner.new(:telephone => '949123456')
=> #<Owner id: nil, telephone: "949123456", created_at: nil, updated_at: nil>
1.9.3-p362 :002 > a.valid?
Owner Exists (0.1ms) SELECT 1 AS one FROM "owners" WHERE "owners"."telephone" = '+421949123456' LIMIT 1
=> false
1.9.3-p362 :003 > a
=> #<Owner id: nil, telephone: "421949123456", created_at: nil, updated_at: nil>
The same, when I save unique number:
1.9.3-p362 :006 > a.telephone = '949123457'
=> "949123457"
1.9.3-p362 :007 > a.save
(0.1ms) begin transaction
Owner Exists (0.2ms) SELECT 1 AS one FROM "owners" WHERE "owners"."telephone" = '+421949123457' LIMIT 1
SQL (2.3ms) INSERT INTO "owners" ("created_at", "telephone", "updated_at") VALUES (?, ?, ?) [["created_at", Wed, 16 Jan 2013 11:55:44 UTC +00:00], ["telephone", "421949123457"], ["updated_at", Wed, 16 Jan 2013 11:55:44 UTC +00:00]]
(88.3ms) commit transaction
=> true
Rails (3.2.11) omits '+' in the beginning of number. Type of number is string. It also saves it without plus sign (if it is unique), but when validating, it calls with plus sign.
What am I doing wrong?
It think telephone column in database is integer type. So the string you have passed is out of its range. That's why you have face this problem.
Unfortunetaly there was bug in my validates_telephone_number_of validator. It had modified attribute :-/
Say
> a = 'aaa' # => 'aaa'
> b = a.to_s # => 'aaa'
> b << 'c' # => 'aaac'
> b # => 'aaac'
> a # => 'aaac'
It is needed to use b = a.to_s.dup.

how to override model validation messages in rails 3

I have a model,group_question_answer.rb
class GroupQuestionAnswer < ActiveRecord::Base
belongs_to :group_question
validates_presence_of :answer
validates_presence_of :answer_question
end
for attribute answer and answer_question i get error message as Group question answers answer can't be blank
I need to show only answer cant be blank.i even tried adding :message=>"cant be blank",but still i dont get my required message.how can i remove model name and can just arrtibute error message ....
class GroupQuestionAnswer < ActiveRecord::Base
attr_accessible :answer
validate do |group_question_answer|
errors.add(:base, "answer can't be blank") if group_question_answer.answer.blank?
end
end
works perfectly
rails c
Loading development environment (Rails 3.2.9)
irb(main):001:0> q = GroupQuestionAnswer.create
(0.1ms) begin transaction
(0.1ms) rollback transaction
=> #<GroupQuestionAnswer id: nil, answer: nil, created_at: nil, updated_at: nil>
irb(main):002:0> q
=> #<GroupQuestionAnswer id: nil, answer: nil, created_at: nil, updated_at: nil>
irb(main):003:0> q.save
(0.1ms) begin transaction
(0.1ms) rollback transaction
=> false
irb(main):004:0> q.errors
=> #<ActiveModel::Errors:0x007fc2fb325fa8 #base=#<GroupQuestionAnswer id: nil, answer: nil, created_at: nil, updated_at: nil>, #messages={:base=>["answer can't be blank"]}>
irb(main):006:0> q.errors.messages
=> {:base=>["answer can't be blank"]}
=> {:base=>["answer can't be blank"]}
irb(main):007:0> q = GroupQuestionAnswer.create(answer: "123")
(0.1ms) begin transaction
SQL (9.0ms) INSERT INTO "group_question_answers" ("answer", "created_at", "updated_at") VALUES (?, ?, ?) [["answer", "123"], ["created_at", Fri, 28 Dec 2012 11:01:38 UTC +00:00], ["updated_at", Fri, 28 Dec 2012 11:01:38 UTC +00:00]]
(1.1ms) commit transaction
=> #<GroupQuestionAnswer id: 1, answer: "123", created_at: "2012-12-28 11:01:38", updated_at: "2012-12-28 11:01:38">
irb(main):008:0> q.errors.messages
=> {}
In my opinion validate method perfect way to fully customize rails validations and that does exactly what you ask for.
You can try like this:
validates :answer, presence: { message: '<Your message>'}
validates :answer_question, presence: { message: '<Your message>'}
Try adding them in your config/locales/en.yml file
As there you can do something like this,
en:
errors:
messages:
answer: answer can't be blank

Resources