How to update attributes only if the params are defined? - ruby-on-rails

currently in my update controller method I have:
#group.attributes = {
:title => params[:group][:title],
:description => params[:group][:description],
:password_required => params[:group][:password_required],
:password => params[:group][:password],
:archived => params[:group][:archived]
}
The problem is that this method is used in multiple places and all of these params are not always passed which results in a "nil" which causes the db commit to rollback.
How can you set attributes only when they are defined w/o having to use if blocks?
Thanks

Could probably do something lousy like this:
#group.attributes = {
:title => params[:group][:title] || #group.title,
:description => params[:group][:description] || #group.description,
:password_required => params[:group][:password_required] || #group.password_required,
:password => params[:group][:password] || #group.password,
:archived => params[:group][:archived] || #group.archived
}
This kind of ugly code is not recommended, but it answers the question of how to do this without explicit if blocks.

why not simplify it with
#group.update_attributes(params[:group])
this way if the value us nil it wont be updated

Related

How to update values that depend on strong params

I have an action (using strong parameters) in controller:
def home_task_params
params.require(:home_task).permit(:subject, :description, :data)
end
I want to modify the data before recording to the database. I want to do something similar to this:
def create
#home_task = HomeTask.create(
:subject => home_task_params.subject,
:description => home_task_params.description,
:day => home_task_params.data,
:data => home_task_params.data,
:class_room => current_user.class_room
)
end
How do I implement it?
params is an object that behaves like a hash. Therefore you cannot read values from that object like this params.subject instead, you have to use params[:subject].
Something like this might work:
#home_task = HomeTask.create(
:subject => home_task_params[:subject],
:description => home_task_params[:description],
:day => home_task_params[:data],
:data => home_task_params[:data],
:class_room => current_user.class_room
)
Or you could just merge the additional values to params:
#home_task = HomeTask.create(
home_task_params.merge(
day: home_task_params[:data],
class_room: current_user.class_room
)
)

Rails form inputs using context validation

In my app I have a validation rule like this
validates_presence_of :name, :on => :custom_context
When I'm saving my data I use
#obj.save(:context => :custom_context)
So that my context validation rule is applied. This works fine. By in my form, the name field is not marked with asterisk. How can I tell my form helper that we are in the :custom_context context and the name field must be marked as required?
I did not understand what you are trying to do BUT understood the scenario.
You can use an attribute_accessor in your model say -
attribute_accessor :context
In your view(.html.erb file) do the following inside your <% form_for %>
<%= f.hidden_field :context, :value => "custom_context" %>
And in your model :
validates_presence_of :name, :if => Proc.new { |variable|
variable.context == "custom_context"}
I think this should help :D
OK, I guess there is no perfect way to do this. Eventually I did something like this:
<%= f.input :name, :required => required_in_context?(:name, :custom_context) %>
And I wrote a helper method:
def required_in_context? field, context
required = false
MyClass.validators.each do |v|
required = true if v.kind == :presence && v.attributes.include?(field) && v.options == {:on => context}
end
required
end

Avoiding Nil errors from a form parameter when using a default value for a text_field?

Rails 2.3.5
If below I'm using either a default session value or (with priority) a form parameter, is there a way to write the code below to avoid a nil error?
<%= f.text_field :deliver_to_addr, :size => 100, :maxlength => 100, :value => params[:request][:delivery_to_address] || session[:address] %>
I worked around the problem by putting a logic block in the controller to come out with a single variable to hold what should be selected (below), but is there a simple way to get around this problem so I don't need a block of code every time I need to use a default value (session[:address] in this case)?
if !params[:request].blank?
if !params[:request][:delivery_to_address].blank?
#delivery_addr_to_select = params[:request][:delivery_to_address]
else
#delivery_addr_to_select = session[:address]
end
else
#delivery_addr_to_select = session[:address]
end
<%= f.text_field :deliver_to_addr, :size => 100, :maxlength => 100, :value => #delivery_addr_to_select %>
Thanks!
You can use the build in try-method:
#delivery_addr_to_select = params[:request].try(:[], :delivery_to_address) || session[:address]
This will try to invoke the [] hash method with :delivery_to_address if the result is nil it will take the session[:address].
You might try the gem andand to help shorten the logic to
#delivery_addr_to_select = params[:request].andand[:delivery_to_address] || session[:address]
This works whether or not :request is present because andand will only invoke :delivery_to_address if params[:request] is not nil.

Passing different parameter to a method call depending on a condition in Ruby

This is the code for my function, in which I am making a call to new
def create_person_detail_from_registration(type, registration, registration_detail)
person_detail = type.constantize.new(
:email => registration.email_2,
:phone_1 => registration_detail.phone_1,
:phone_2 => registration_detail.phone_2,
:phone_3 => registration_detail.phone_3,
:phone_4 => registration_detail.phone_4,
:phone_5 => registration_detail.phone_5,
:phone_6 => registration_detail.phone_6,
:phone_7 => registration_detail.phone_7,
:address_1 => registration_detail.address_1,
:address_2 => registration_detail.address_2,
:city => registration_detail.city,
:state => registration_detail.state,
:postal_code => registration_detail.postal_code,
:country => registration_detail.country
)
return person_detail
end
Now the issue is depending on what value type has, :email is either set to registration.email_2 or registration.email. One way of doing that is of course, to write the whole code twice surrounded by an if-elsif statement. But I just wanna know, if there's any smarter, more elegant way of doing this?
Just add the condition into value .
:email => (type==1 ? registration.email_2 : registration.email),

Passing extra data to find_or_create

Something I've always wondered about rails is the ability to pass extra data to find_or_create methods in rails. For example, I can't do the following
User.find_or_create_by_name('ceilingfish', :email => 'an_email#a.domain', :legs => true, :face => false)
I could do
u = User.find_or_create_by_name('ceilingfish')
u.update_attributes(:email => 'an_email#a.domain', :legs => true, :face => false)
But that's uglier, and also requires three queries. I suppose I could do
User.find_or_create_by_name_and_email_and_face_and_legs('ceilingfish','an_email#a.domain',true, false)
But that kind of implies that I know what the values of email, legs and face are. Does anyone know if there's a really elegant way of doing this?
Try this:
User.find_or_create_by_name(:name=>'ceilingfish',
:email => 'an_email#a.domain', :legs => true, :face => false)
When you have additional parameters to find_or_create_by_, you have to pass all the parameters as a hash.
Rails 4
User.create_with(
email: 'an_email#a.domain',
legs: true, face:false
).find_or_create_by(:name=>'ceilingfish')
With rails 4.x
DEPRECATION WARNING: This dynamic method is deprecated. Please use e.g. Post.find_or_create_by(name: 'foo') instead
Use this
User.find_or_create_by(first_name: 'Scarlett') do |user|
user.last_name = 'Johansson'
end

Resources