I am tried to update attribute normally but it is not updating.
Here is my customer model
class Customer < ActiveRecord::Base
attr_accessible :name, :phone_number, :email
attr_accessible :first_name
attr_accessible :last_name
before_validation :parse_name
def name
"#{first_name} #{last_name}".strip
end
private
def parse_name
if attributes['name'].present?
self.first_name, self.last_name = attributes['name'].strip.split(' ', 2)
end
end
end
I tried to update first_name and last_name but it is not updating but if I tried to update email it is updating fine
Here is my rails console trace
Updating email
2.1.0dev :004 > a = Customer.find(5)
Customer Load (0.2ms) SELECT `customers`.* FROM `customers` WHERE `customers`.`id` = 5 LIMIT 1
=> #<Customer id: 5, name: "First Last", phone_number: "1234567890", created_at: "2014-09-15 12:48:30", updated_at: "2014-09-15 14:32:17", first_name: "Fir
2.1.0dev :008 > a = Customer.find(5)
Customer Load (0.1ms) SELECT `customers`.* FROM `customers` WHERE `customers`.`id` = 5 LIMIT 1
=> #<Customer id: 5, name: "First Last", phone_number: "1234567890", created_at: "2014-09-15 12:48:30", updated_at: "2014-09-15 14:32:17", first_name: "Fir
st", last_name: "Last", email: "shri#mail.com">
2.1.0dev :009 > a.email = "Test#test.com"
=> "Test#test.com"
2.1.0dev :010 > a.save
(0.2ms) BEGIN
Customer Exists (0.2ms) SELECT 1 AS one FROM `customers` WHERE (`customers`.`phone_number` = BINARY '1234567890' AND `customers`.`id` != 5) LIMIT 1
(0.4ms) UPDATE `customers` SET `email` = 'Test#test.com', `updated_at` = '2014-09-15 20:38:31' WHERE `customers`.`id` = 5
(104.9ms) COMMIT
=> true
2.1.0dev :011 > a
=> #<Customer id: 5, name: "First Last", phone_number: "1234567890", created_at: "2014-09-15 12:48:30", updated_at: "2014-09-15 20:38:31", first_name: "Fir
st", last_name: "Last", email: "Test#test.com">
But for updating first_name and last_name is not working
updating last_name
2.1.0dev :012 > a.last_name = "last_name"
=> "last_name"
2.1.0dev :013 > a.save
(0.2ms) BEGIN
Customer Exists (0.7ms) SELECT 1 AS one FROM `customers` WHERE (`customers`.`phone_number` = BINARY '1234567890' AND `customers`.`id` != 5) LIMIT 1
(0.2ms) COMMIT
=> true
2.1.0dev :014 > a.save!
(0.2ms) BEGIN
Customer Exists (0.2ms) SELECT 1 AS one FROM `customers` WHERE (`customers`.`phone_number` = BINARY '1234567890' AND `customers`.`id` != 5) LIMIT 1
(0.1ms) COMMIT
=> true
2.1.0dev :015 > a
=> #<Customer id: 5, name: "First Last", phone_number: "1234567890", created_at: "2014-09-15 12:48:30", updated_at: "2014-09-15 20:38:31", first_name: "Fir
st", last_name: "Last", email: "Test#test.com">
Using update attributes
2.1.0dev :016 > a.update_attributes(:first_name => "test_name", :last_name => "test_name")
(0.2ms) BEGIN
Customer Exists (0.2ms) SELECT 1 AS one FROM `customers` WHERE (`customers`.`phone_number` = BINARY '1234567890' AND `customers`.`id` != 5) LIMIT 1
(0.2ms) COMMIT
=> true
2.1.0dev :017 > a
=> #<Customer id: 5, name: "First Last", phone_number: "1234567890", created_at: "2014-09-15 12:48:30", updated_at: "2014-09-15 20:38:31", first_name: "Fir
st", last_name: "Last", email: "Test#test.com">
I tried to resolve it but it is not working.
Can any please tell me what I am missing.
I am using rails 3.2.14 and rails 2.1.0
You have a before_validation method where first and last name are set depending on name. Your record already has a name, so it splits this name and extract first and last name.
Your before_validation is overwriting the value you want to set. I would remove the parse name method all together and have the #name method simply be a calculated value based on first_name and last_name e.g.
class Customer < ActiveRecord::Base
attr_accessible :phone_number, :email, :first_name, :last_name
def name
"#{first_name} #{last_name}".strip
end
end
If you really must have #name= I would do it as
def name=(name_string)
self.first_name, self.last_name = name_string.strip.split(' ', 2)
end
You will have to save for these values to hold. You could also do something like.
def update_name(name_string)
update_attributes(Hash[[:first_name,:last_name].zip(name_string.strip.split(' ', 2))])
end
Which will run save with and return true or false based on validity
Related
guys.
I have a model Order with attrbutes :name, :phone, :product_id
How to save in database only unique objects of Order - with unique combination of :name, :phone and :product?
In example:
already in db:
Order name: 'Bob', phone: '123', product_id: '4'
must not been saved:
Order name: 'Bob', phone: '123', product_id: '4'
must be saved:
Order name: 'Bob', phone: '123', product_id: '5'
must be saved:
Order name: 'Bob', phone: '1234', product_id: '4'
Try to set a unique validation with scope. Docs are here
class Order < ActiveRecord::Base
validates :name, uniqueness: { scope: [:phone, :product_id], message: "Not UNIQ" }
end
Here is a result:
[29] pry(main)> Order.all
Order Load (0.3ms) SELECT "orders".* FROM "orders"
=> [#<Order:0x007fd07cc6fd00 id: 1, name: "Bob", phone: "1234", product_id: 4, created_at: Thu, 11 Aug 2016 02:56:22 UTC +00:00, updated_at: Thu, 11 Aug 2016 02:56:22 UTC +00:00>]
[30] pry(main)> o1 = Order.new(name:"Bob", phone:"1234", product_id: 4)
=> #<Order:0x007fd07d5f3390 id: nil, name: "Bob", phone: "1234", product_id: 4, created_at: nil, updated_at: nil>
[31] pry(main)> o1.valid?
Order Exists (0.4ms) SELECT 1 AS one FROM "orders" WHERE ("orders"."name" = 'Bob' AND "orders"."phone" = '1234' AND "orders"."product_id" = 4) LIMIT 1
=> false
[32] pry(main)> o1.errors
=> #<ActiveModel::Errors:0x007fd07d65b580 #base=#<Order:0x007fd07d5f3390 id: nil, name: "Bob", phone: "1234", product_id: 4, created_at: nil, updated_at: nil>, #messages={:name=>["Not UNIQ"]}>
[33] pry(main)> o2 = Order.new(name:"Bob", phone:"12345", product_id: 4)
=> #<Order:0x007fd07cc7f3e0 id: nil, name: "Bob", phone: "12345", product_id: 4, created_at: nil, updated_at: nil>
[34] pry(main)> o2.valid?
Order Exists (0.4ms) SELECT 1 AS one FROM "orders" WHERE ("orders"."name" = 'Bob' AND "orders"."phone" = '12345' AND "orders"."product_id" = 4) LIMIT 1
=> true
I'm having a hard time with Rails and nested attributes and would really appreciate some help.
Here is the output from my console session where I was attempting to get the updated values to save but as you can see, they don't seem to take on the next line when I perform the find again:
irb(main):070:0* e = Equipment.find(26)
Equipment Load (0.5ms) SELECT "equipment".* FROM "equipment" WHERE "equipment"."id" = $1 LIMIT 1 [["id", 26]]
=> #<Equipment id: 26, name: "fdsfsdsdfsd2", created_at: "2015-11-02 15:26:43", updated_at: "2015-11-02 16:38:55", site_id: 57, type_id: 3>
irb(main):071:0> e.update({"name"=>"fdsfsdsdfsd2", "site_id"=>"57", "type_id"=>"3", "equipment_properties_attributes"=>{"0"=>{"id"=>"15", "value"=>"2015-10-34", "property_id"=>"4"}, "1"=>{"id"=>"16", "value"=>"fsdfdsfsd", "property_id"=>"5"}}})
(0.6ms) BEGIN
EquipmentProperty Load (0.7ms) SELECT "equipment_properties".* FROM "equipment_properties" WHERE "equipment_properties"."equipment_id" = $1 AND "equipment_properties"."id" IN (15, 16) [["equipment_id", 26]]
(0.2ms) COMMIT
=> true
irb(main):072:0> e.equipment_properties
EquipmentProperty Load (0.5ms) SELECT "equipment_properties".* FROM "equipment_properties" WHERE "equipment_properties"."equipment_id" = $1 [["equipment_id", 26]]
=> #<ActiveRecord::Associations::CollectionProxy [#<EquipmentProperty id: 15, equipment_id: 26, property_id: 4, value: "2015-10-34", created_at: "2015-11-02 15:26:51", updated_at: "2015-11-02 15:26:51">, #<EquipmentProperty id: 16, equipment_id: 26, property_id: 5, value: "fsdfdsfsd", created_at: "2015-11-02 15:26:51", updated_at: "2015-11-02 15:26:51">]>
irb(main):073:0> e = Equipment.find(26)
Equipment Load (0.5ms) SELECT "equipment".* FROM "equipment" WHERE "equipment"."id" = $1 LIMIT 1 [["id", 26]]
=> #<Equipment id: 26, name: "fdsfsdsdfsd2", created_at: "2015-11-02 15:26:43", updated_at: "2015-11-02 16:38:55", site_id: 57, type_id: 3>
irb(main):074:0> e.equipment_properties
EquipmentProperty Load (0.6ms) SELECT "equipment_properties".* FROM "equipment_properties" WHERE "equipment_properties"."equipment_id" = $1 [["equipment_id", 26]]
=> #<ActiveRecord::Associations::CollectionProxy [#<EquipmentProperty id: 15, equipment_id: 26, property_id: 4, value: "2015-10-30", created_at: "2015-11-02 15:26:51", updated_at: "2015-11-02 15:26:51">, #<EquipmentProperty id: 16, equipment_id: 26, property_id: 5, value: "fsdfdsfsd", created_at: "2015-11-02 15:26:51", updated_at: "2015-11-02 15:26:51">]>
The same thing is happening with the web interface. I can provide additional details if anyone needs them but I am allowing the parameters through and on creation, the initial values are saved.
I've been beating my head against this all morning and I suspect it is something stupid but I'm just not sure what to try next. Thanks!
UPDATE 1:
Equipment Model:
class Equipment < ActiveRecord::Base
belongs_to :site
belongs_to :type
has_and_belongs_to_many :properties
has_many :equipment_properties
accepts_nested_attributes_for :equipment_properties, reject_if: :all_blank, allow_destroy: true
end
And also the equipment_properties model:
class EquipmentProperty < ActiveRecord::Base
belongs_to :equipment
belongs_to :property
has_one :type, through: :equipment
end
Also, of relevance might be that I can update the individual equipment_property without nesting and that does work.
UPDATE 2:
I managed to add this to the controller and it saves the values now. Not pretty but it works I guess...
equipment_params[:equipment_properties_attributes].each do |property|
ep = EquipmentProperty.where(id: property[1][:id]).first
#logger.debug "EP Value: #{ep.value}"
#logger.debug "Property Value: #{property[1][:value]}"
ep.value = property[1][:value]
ep.save
end
This is what I ended up adding to the controller to resolve this. Definitely a hack though and I'm not sure why the updates are taking:
equipment_params[:equipment_properties_attributes].each do |property|
ep = EquipmentProperty.where(id: property[1][:id]).first
#logger.debug "EP Value: #{ep.value}"
#logger.debug "Property Value: #{property[1][:value]}"
ep.value = property[1][:value]
ep.save
end
I have 2 models with a one-to-many association: User and Recipe. the User class has_many :recipes while the Recipe class belongs_to :user. I've already run the migration, reloaded the rails console, and checked to make sure that user_id is a column in the recipes table. Still, I get an undefined method error when I try to append a recipe to a user:
2.0.0-p598 :047 > user.recipes << Recipe.first
NoMethodError: undefined method `recipes' for #<User:0x00000004326fa0>
here is the migration code (I've already run rake db:migrate):
class AddUserIdToRecipes < ActiveRecord::Migration
def change
add_column :recipes, :user_id, :integer
end
end
Here is the User model code:
class User < ActiveRecord::Base
has_one :profile
has_many :recipes
end
Here is the Recipe model code:
class Recipe < ActiveRecord::Base
validates_presence_of :title, :body
belongs_to :user
def long_title
"#{title} - #{published_at}"
end
end
Why does recipes still show up as an undefined method?
Try this on your console:
irb(main):007:0> user = User.new first_name: 'John', last_name: 'Doe'
=> #<User id: nil, first_name: "John", last_name: "Doe", created_at: nil, updated_at: nil>
irb(main):008:0> user.save
(0.1ms) begin transaction
SQL (0.6ms) INSERT INTO "users" ("created_at", "first_name", "last_name", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2015-01-19 21:14:33.489371"], ["first_name", "John"], ["last_name", "Doe"], ["updated_at", "2015-01-19 21:14:33.489371"]]
(0.6ms) commit transaction
=> true
irb(main):009:0> r = Recipe.new name: 'oooohh awesome', description: 'my description goes here'
=> #<Recipe id: nil, name: "oooohh awesome", description: "my description goes here", created_at: nil, updated_at: nil, user_id: nil>
irb(main):010:0> r.save
(0.1ms) begin transaction
SQL (0.2ms) INSERT INTO "recipes" ("created_at", "description", "name", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2015-01-19 21:15:16.548090"], ["description", "my description goes here"], ["name", "oooohh awesome"], ["updated_at", "2015-01-19 21:15:16.548090"]]
(1.2ms) commit transaction
=> true
irb(main):011:0> user.recipes << Recipe.first
Recipe Load (0.2ms) SELECT "recipes".* FROM "recipes" ORDER BY "recipes"."id" ASC LIMIT 1
(0.0ms) begin transaction
SQL (0.2ms) UPDATE "recipes" SET "updated_at" = ?, "user_id" = ? WHERE "recipes"."id" = 1 [["updated_at", "2015-01-19 21:15:49.181586"], ["user_id", 1]]
(1.3ms) commit transaction
Recipe Load (0.2ms) SELECT "recipes".* FROM "recipes" WHERE "recipes"."user_id" = ? [["user_id", 1]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Recipe id: 1, name: "oooohh awesome", description: "sper long deskdk", created_at: "2015-01-19 21:10:24", updated_at: "2015-01-19 21:15:49", user_id: 1>]>
irb(main):012:0> user.save
(0.1ms) begin transaction
(0.0ms) commit transaction
=> true
irb(main):013:0> user.recipes
=> #<ActiveRecord::Associations::CollectionProxy [#<Recipe id: 1, name: "oooohh awesome", description: "sper long deskdk", created_at: "2015-01-19 21:10:24", updated_at: "2015-01-19 21:15:49", user_id: 1>]>
irb(main):014:0> user.recipes.first
=> #<Recipe id: 1, name: "oooohh awesome", description: "sper long deskdk", created_at: "2015-01-19 21:10:24", updated_at: "2015-01-19 21:15:49", user_id: 1>
irb(main):015:0>
you can see that Recipe.first has been inserted into user.recipes and its saved.
I made two models similar to yours, and have exactly the same setup as you. You can follow code above to write your controllers.
This question already has an answer here:
Why can't I create active records that count for something in rspec?
(1 answer)
Closed 8 years ago.
I can create users in the console find with:
2.0.0-p247 :020 > User.create(username: 'user30', password: 'abc123', admin: true)
(0.3ms) BEGIN
User Exists (0.6ms) SELECT 1 AS one FROM `users` WHERE `users`.`username` = BINARY 'user30' LIMIT 1
SQL (0.5ms) INSERT INTO `users` (`admin`, `created_at`, `pwd_hashed`, `salt`, `updated_at`, `username`) VALUES (NULL, '2014-07-17 01:34:41', 'd3272da7e3fc0f6e1b035dfb10e6f412ae84fac8', '415066400.06787292634781616', '2014-07-17 01:34:41', 'user30')
(75.6ms) COMMIT
=> #<User id: 14, username: "user30", pwd_hashed: "d3272da7e3fc0f6e1b035dfb10e6f412ae84fac8", salt: "415066400.06787292634781616", created_at: "2014-07-17 01:34:41", updated_at: "2014-07-17 01:34:41", admin: nil>
2.0.0-p247 :021 > User.create(username: 'user31', password: 'abc123', admin: true)
(0.3ms) BEGIN
User Exists (1.4ms) SELECT 1 AS one FROM `users` WHERE `users`.`username` = BINARY 'user31' LIMIT 1
SQL (0.4ms) INSERT INTO `users` (`admin`, `created_at`, `pwd_hashed`, `salt`, `updated_at`, `username`) VALUES (NULL, '2014-07-17 01:34:46', '1ea5630a3c28b36e714625c4b44f3f951ef16c7a', '416177200.3102826047096757', '2014-07-17 01:34:46', 'user31')
(77.5ms) COMMIT
=> #<User id: 15, username: "user31", pwd_hashed: "1ea5630a3c28b36e714625c4b44f3f951ef16c7a", salt: "416177200.3102826047096757", created_at: "2014-07-17 01:34:46", updated_at: "2014-07-17 01:34:46", admin: nil>
2.0.0-p247 :022 > User.create(username: 'user32', password: 'abc123', admin: true)
(0.3ms) BEGIN
User Exists (0.6ms) SELECT 1 AS one FROM `users` WHERE `users`.`username` = BINARY 'user32' LIMIT 1
SQL (0.6ms) INSERT INTO `users` (`admin`, `created_at`, `pwd_hashed`, `salt`, `updated_at`, `username`) VALUES (NULL, '2014-07-17 01:34:50', '9aeb6cfcb80f57a08c421999dcfb5ad332317789', '417559200.14647833904112617', '2014-07-17 01:34:50', 'user32')
(12.0ms) COMMIT
=> #<User id: 16, username: "user32", pwd_hashed: "9aeb6cfcb80f57a08c421999dcfb5ad332317789", salt: "417559200.14647833904112617", created_at: "2014-07-17 01:34:50", updated_at: "2014-07-17 01:34:50", admin: nil>
2.0.0-p247 :023 >
2.0.0-p247 :005 > User.count
(0.6ms) SELECT COUNT(*) FROM `users`
=> 3
but in rspec when I have
describe "keep admin" do
its "Can't delete the only admin" do
user1 = User.create(username: 'user1', password: 'abc123', admin: true)
user2 = User.create(username: 'user2', password: 'def456', admin: true)
user3 = User.create(username: 'user3', password: 'ghi798', admin: true)
expect(User.where(admin: true).count).to eq 3
end
end
why do I get 0 instead of 3:
Failures:
1) keep admin Can't delete the only admin should eq 3
Failure/Error: expect(User.where(admin: true).count).to eq 3
expected: 3
got: 0
(compared using ==)
# ./spec/models/user_spec.rb:24:in `block (2 levels) in <top (required)>'
Finished in 0.37602 seconds
5 examples, 1 failure
User model:
$ cat app/models/user.rb
class User < ActiveRecord::Base
require 'digest/sha1'
attr_accessor :password_confirmation
attr_accessor :admin
validates_presence_of :username
validates_uniqueness_of :username
validates_confirmation_of :password
validate :password_non_blank
def self.delete_me(user)
how_many_admins = User.where(admin: true).count
if how_many_admins > 1
puts "delete ok!"
user.delete
else
puts "delete not ok!"
end
end
def self.authenticate(name, password)
user = self.find_by_username(name)
if user
expected_password = encrypted_password(password, user.salt)
if user.pwd_hashed != expected_password
user = nil
end
end
user
end
def password
#password
end
def password=(pwd)
#password = pwd
return if pwd.blank?
create_new_salt
self.pwd_hashed = User.encrypted_password(self.password, self.salt)
end
def is_admin
admin ? 'Yes' : 'No'
end
private
def password_non_blank
errors.add(:password, "Missing password") if pwd_hashed.blank?
end
def create_new_salt
self.salt = self.object_id.to_s + rand.to_s
end
def self.encrypted_password(password, salt)
string_to_hash = password + "wibble" + salt
Digest::SHA1.hexdigest(string_to_hash)
end
end
It appears your admin assignment in your create call isn't working. In your console you set admin: true in all of your users, yet look at the log:
User.create(username: 'user30', password: 'abc123', admin: true)
#<User id: 14, username: "user30", pwd_hashed: "d3272da7e3fc0f6e1b035dfb10e6f412ae84fac8", salt: "415066400.06787292634781616", created_at: "2014-07-17 01:34:41", updated_at: "2014-07-17 01:34:41", admin: nil>
admin: nil is what is being stored.
You're trying to set a ruby boolean value into what I'm guessing is a "string" field in the database? If so, try this:
User.create(username: 'user30', password: 'abc123', admin: "true")
Then change your rspec test to:
expect(User.where(admin: "true").count).to eq(3)
When I retrieve a contact like this...
c = Contact.where(:user_id => 37)
I can't take advantage of the association the contact has with the Province.rb model, as c.province would produce a no method error.
Contact Load (0.2ms) SELECT "contacts".* FROM "contacts" WHERE "contacts"."user_id" = 37
=> [#<Contact id: 13, firm: "aldjflkads", address: "55 SO Avenue", city: "Toronto", postalcode: "M3A B2B", mobile: "999 999 999", office: "", user_id: 37, created_at: "2013-05-02 18:52:01", updated_at: "2013-05-02 18:52:01", province_id: 6>]
>> c.province
NoMethodError: undefined method `province' for #<ActiveRecord::Relation:0x007fbe94bd9cf0>
However, when I find a contact by user id this way....
>> c = Contact.find_by_user_id(37)
I can then call c.province and c.province.name
Contact Load (0.3ms) SELECT "contacts".* FROM "contacts" WHERE "contacts"."user_id" = 37 LIMIT 1
=> #<Contact id: 13, firm: "aldjflkads", address: "55 aldjfla;skfj", city: "Toronto", postalcode: "M4G B2B", mobile: "999 999 999", office: "", user_id: 37, created_at: "2013-05-02 18:52:01", updated_at: "2013-05-02 18:52:01", province_id: 6>
>> c.province
Province Load (0.2ms) SELECT "provinces".* FROM "provinces" WHERE "provinces"."id" = 6 LIMIT 1
=> #<Province id: 6, name: "Ontario", created_at: "2013-04-19 02:37:11", updated_at: "2013-04-19 02:37:11">
>> c.province.name
=> "Ontario"
Question: Is there a way I can take advantage of association methods if I retrieve data like this
Contact.where(:user_id => 37)
Update
My Contact.rb model belongs_to :provinces, however, there's other data (address, postal code etc) that's native to the contact model. Therefore, if I did this (as suggested in the first answer), it would only allow me to access the province, not any of the other details I need.
#contactdetails = Contact.where({:user_id => #user.id}).first.province
c = Contact.where(:user_id => 37).first.province
where() returns a collection.. whereas find_by_id assumes a unique result and only returns one