Rails update_attributes not working - ruby-on-rails

In my Rails app, update_attribute seems not working. I'm trying to update a boolean field called billed. The same command works great for two other tables.
Output of rails console:
>> Expense.find(28).update_attributes(:billed => true)
=> false
>> Expense.find(28).billed
=> false
expenses_controller.rb:
# PUT /expenses/1
# PUT /expenses/1.json
def update
#expense = Expense.find(params[:id])
respond_to do |format|
if #expense.update_attributes(params[:expense])
format.html { redirect_to #expense, notice: 'Expense was successfully updated.' }
format.json { render json: #expense }
else
format.html { render action: "edit" }
format.json { render json: #expense.errors, status: :unprocessable_entity }
end
end
end
Expenses has these validations:
validates_presence_of :employee_id # Declare a required field
validates_presence_of :unitcost # Declare a required field
validates_presence_of :quantity # Declare a required field
validates_presence_of :exp_date # Declare a required field
validates_presence_of :category_id # Declare a required field
validates_presence_of :description # Declare a required field
validates_presence_of :markup # Declare a required field
validates :markup, :format => { :with => /^\d{3}$/}, :numericality => {:greater_than => 0}
validates :unitcost, :format => { :with => /\A\d+(?:\.\d{0,2})?\z/}, :numericality => {:greater_than => 0}
validates_numericality_of :quantity, :only_integer => true, :message => "Can only be whole number."
Thanks for the help!

Use update_attribute instead of update_attributes to update single column.
From the API
update_attribute
Updates a single attribute and saves the record without going through
the normal validation procedure. This is especially useful for boolean
flags on existing records. The regular update_attribute method in Base
is replaced with this when the validations module is mixed in, which
it is by default
Expense.find(28).update_attribute(:billed => true)

Related

Rails Mongodb can't save record

I'm using Mongodb in my Rails app. I have 2 models, which are Account and User. Account has many users and users belongs to account.
Account model
has_many :users, :inverse_of => :account, :dependent => :destroy
validates :organization_name, presence: true, uniqueness: true
User model
belongs_to :account, :inverse_of => :users
validates :account, :presence => false
validates :email, presence: true
has_secure_password
validates :password, length: { minimum: 6 }, allow_nil: true
def User.new_token
SecureRandom.urlsafe_base64
end
def self.create_with_password(attr={})
generated_password = attr[:email] + User.new_token
self.create!(attr.merge(password: generated_password, password_confirmation: generated_password))
end
User controller
def new
#user = User.find_by(params[:id])
#user = #current_user.account.users.new
end
def create
#user = User.find_by(params[:id])
#user = #current_user.account.users.create_with_password(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
format.js
else
format.html { render 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
format.js { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:id, :email, :password, :password_confirmation, :owner, :admin)
end
I can successfully sign up an account with a user. But when I tried to add a new user, the user record can't be saved. I assigned a password for users when creating a new user.
The error messages:
message: Validation of User failed. summary: The following errors were found: Account can't be blank resolution: Try persisting the document with valid data or remove the validations.
If I removed the self.create_with_password and manually type in the password in the form, it works. So i guess the error must be in the self create password, it seems like doesn't save the record. By the way I'm using Rails 5.0. Any idea to solve this?
Hey #ternggio Welcome to community.
Account can't be blank.
This error appear due to belongs_to statement in user.rb.
In rails > 5 belongs_to is by default required, You can set as optional with marking optional: true.
belongs_to :account, :inverse_of => :users, optional: true
and remove below line.
validates :account, :presence => false
Hope, this will help you.

Paperclip undefined method `title_file_name' error in Rails 4.0.1

I installed it by following the manual on paperclip github page and I get the given error. What am I doing wrong?
I have 4 input fields: title (text_field), description (text_area), price (text_field) and image (file_field). Why am I even getting this error with the prefix title in it? What has the title field got to do with it, are there any conflicts maybe? I did create and run the migrations so this is realy kind of weird I think.
Any help appreciated. Thanks.
EDIT:
The migration is as follows:
class AddImageColumnsToProducts < ActiveRecord::Migration
def change
add_attachment :products, :image
end
end
It results like so:
image_file_name varchar(255)
image_content_type varchar(255)
image_file_size int(11)
image_updated_at datetime
Model:
class Product < ActiveRecord::Base
has_attached_file :image, :styles => { :medium => "600x600>", :thumb => "258x258>" },
:default_url => "images/:style/:slug.png"
validates :title, :content, :image, :attachment_presence => true
validates_with AttachmentPresenceValidator, :attributes => :image
end
Controller:
def create
#product = Product.new(product_params)
#product.image = params[:product][:image]
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render action: 'show', status: :created, location: #product }
else
format.html { render action: 'new' }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
The issue is with your validation. The line which says
validates :title, :content, :image, :attachment_presence => true
assumes title, content & image as 3 image-based attributes. But, I understand that only 'image' is the image-based field. So, your code should rather be:
validates :title, :content, :presence=>true
validates :image, :attachment_presence => true
Also, I don't see the 'content' field in the request-log. I guess, you mean 'description'. Make sure you have the same attribute-names in the model-validations, database-schema & view files.

ActiveModel::MassAssignmentSecurity::Error in UsersController#create

While applying logging concept to my book catalog display, when a user is regestering I am coming acorss this sort of error.
Can't mass-assign protected attributes: password_confirmation, password
And my code in app/model/user.rb is as follows:
class User < ActiveRecord::Base
attr_accessible :name, :password_digest
validates :name, :presence => true, :uniqueness => true
has_secure_password
end
And my code of create method in app/contollers/user_controller.rb
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to users_url, :notice => 'User #{#user.name} was successfully created.' }
format.json { render :json => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
Any help please!
If you want to assign those values in the way you're doing it, you need to add them to the attr_accessible in your model:
attr_accessible :name, :password_digest, :password, :password_confirmation
I suspect you may not want to assign both of those, so you might want to delete them from that hash first (in the controller):
user = params[:user]
user.delete(:password_confirmation)
#user = User.new(user)
You could also create a new hash containing just the values you want to use to create the new User, if you have only a few values to keep but a lot of values to ignore.
(You could also create a new "empty" User and just assign the values you want - if that makes more sense in your situation.)

Rails 3 - how to skip validation rule?

I have for the registration form this validation rule:
validates :email,
:presence => {:message => 'cannot be blank.'},
:allow_blank => true,
:format => {
:with => /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]+\z/,
:message => 'address is not valid. Please, fix it.'
},
:uniqueness => true
This rule check, if a user fill into the registration form email address (+ its correct format).
Now I am trying to add the opportunity to log in with using Twitter. Twitter doesn't provide user's email address.
How to skip in this case the validation rule above?
You can skip validation while saving the user in your code. Instead of using user.save!, use user.save(:validate => false). Learnt this trick from Railscasts episode on Omniauth
I'm not sure whether my answer is correct, just trying to help.
I think you can take help from this question. If i modify the accepted answer for your question, it will be like (DISCLAIMER: I could not test the following codes as env is not ready in the computer i'm working now)
validates :email,
:presence => {:message => 'cannot be blank.', :if => :email_required? },
:allow_blank => true,
:format => {
:with => /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]+\z/,
:message => 'address is not valid. Please, fix it.'
},
:uniqueness => true
def email_required?
#logic here
end
Now, you update the email_required? method to determine whether it is from twitter or not! If from twitter, return false otherwise true.
I believe, you need use same :if for the :uniqueness validator too. otherwise it will. Though, i'm not sure too :(. Sorry
Skipping Individual Validations
Skipping individual validations requires a bit more work. We need to create a property on our model called something like skip_activation_price_validation:
class Product < ActiveRecord::Base
attr_accessor :skip_activation_price_validation
validates_numericality_of :activation_price, :greater_than => 0.0, unless: :skip_activation_price_validation
end
Next we will set the property to true any time we want to skip validations. For example:
def create
#product = Product.new(product_params)
#product.skip_name_validation = true
if #product.save
redirect_to products_path, notice: "#{#product.name} has been created."
else
render 'new'
end
end
def update
#product = Product.find(params[:id])
#product.attributes = product_params
#product.skip_price_validation = true
if #product.save
redirect_to products_path, notice: "The product \"#{#product.name}\" has been updated. "
else
render 'edit'
end
end
You seem to be doing two separate validations here:
If a user provides an email address, validate it's format and uniqueness
Validate the presence of an email address, unless it's a twitter signup
I would do this as two separate validations:
validates :email,
:presence => {:message => "..."},
:if => Proc.new {|user| user.email.blank? && !user.is_twitter_signup?}
validates :email,
:email => true, # You could use your :format argument here
:uniqueness => { :case_sensitive => false }
:unless => Proc.new {|user| user.email.blank?}
Additional info: validate email format only if not blank Rails 3
The best way would be:
It would validate the email when the user is not signed in from twitter as well as skip email validation when signed from twitter.
validates :email,
:presence => {:message => 'cannot be blank.'},
:allow_blank => true,
:format => {
:with => /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]+\z/,
:message => 'address is not valid. Please, fix it.'
},
:uniqueness => true
unless: Proc.new {|user| user.is_twitter_signup?}

Hiding Rails Model Attributes

I have a controller for an API that looks like this:
def index
respond_to do |format|
format.json { render :json => #groups.to_json(:only => [:id, :name, :description, :created_at, :updated_at])}
end
end
def show
respond_to do |format|
format.json { render :json => #group.to_json(:only => [:id, :name, :description, :created_at, :updated_at]) }
end
end
# #todo add store to item
def create
if #group.save
render :json => #group.to_json(:only => [:id, :name, :description, :created_at, :updated_at])
else
render :status => 406
end
end
def update
if #group.update_attributes(params[:group])
render :json => #group.to_json(:only => [:id, :name, :description, :created_at, :updated_at])
else
render :status => 406
end
end
def destroy
#group.destroy
render :text => ""
end
As you can see, I'm repeating my self a lot. I'd love to make these (and only these) attributes available by way of the model, but couldn't find a fitting solution. Is there anything to protect attributes from mass writing? Or do I possibly mean mass reading?
As noted in comments below I want to have a model with attributes, name and i_am_private. When I render that model as json - render :json => #model - I want only name to show up.
Ruby 1.8.7
Rails 3
How about overriding as_json method in your Group model?
class Group < ActiveRecord:Base
...
def as_json(options={})
{
:id => id,
:name => name,
:description => description,
:created_at => created_at,
:updated_at => updated_at
}
end
end
To prevent mass assignment, add the following to your model:
attr_accessible :attr1, :attr2, :attr3
where attr1, attr2, attr3 and so on are the attributes you want to allow for mass assignment, the rest of the attributes for that model will not be allowed for mass assignment.

Resources