I am receiving an API call at my server with parameters
first_name , :last_name , :age
etc
I want to bind those params to my object against which user is having attribute with same name , like i want to have these in user[first_name] , user[:last_name]
so that I can just put the complete user object into database in following way ,
User.new(params[:user]) or User.new(some_hash)
I dont want to use the following ,
User.new(:first_name=>params[:first_name],:last_name=>params[:last_name])
thanks in advance for you help :)
Something like this may work:
user = User.new
params.each do |key,value|
user[key] = value if user.attribute_names.include?(key.to_s)
end
Note, however, that you should protect sensitive attributes of your User model with attr_protected or attr_accessible in this case.
Writing that functionality into User.initialize can take care of this:
def initialize(args={})
args.each_with_key do |key,val|
instance_variable_set("##{key}", val)
end
end
This of course has no validation and does not protect your object from bad data. For example, if you want to make sure only valid accessible attributes are being set, add if respond_to? key to end end of line 3.
Related
I am using this function to find users, which i am using .require only worked when i sent both or at least one parameter but if i send empty i got errors, It should not be mandatory to send parameters
def find_params
params.require(:person).permit(:name, :age)
end
if i send the name or age i will work, but if i send nothing i am getting this error
params is missing
if i send empty like this:
{} or null it should work correctly returning all the users
or should not i use this to search users?
params.require(:person).permit(:name, :age)
might i have to user like this?
params[:name] and params[:age]
i am working with reactjs
i am sending the payload liket this:
{name:"ed", age:"12", skin:"black", weight: "180lbs", height:"183"}
Rails' StrongParameters were built for a very specific use:
It provides an interface for protecting attributes from end-user assignment. This makes Action Controller parameters forbidden to be used in Active Model mass assignment until they have been explicitly enumerated.
That means when you use the params just to read from the database, then there is no need (and hardly any advantage) to use StrongParameters.
Instead, I would just use the params directly in the controller like this:
def index
#users = User
.filter_by(:name, params.dig(:person, :name))
.filter_by(:age, params.dig(:person, :age))
# ...
end
And to make this work you will need to define an filter_by scope in your app/models/user.rb:
scope :filter_by, -> (attr, value) { where(attr => value) if value.present? }
The whole point of using ActionController::Parameters#require is to cause your create/update method to bail early if the parameter you expect to be a hash isn't sent at all since there is no point in proessing the request further and this prevents a potential uncaught nil error.
If you want to allow a key to be null use #fetch instead:
params.fetch(:person, {})
.permit(:name, :age)
#fetch allows you to pass a second key which is the default value and it returns a new ActionController::Parameters instance.
But it looks like you're actually sending flat parameters which are not nested in which case you don't need fetch either:
params.permit(:name, :age)
Note that Rails by default has parameters wrapping turned on for JSON requests and both will very likely work.
You can use Find User
Routes.rb
get "search_user", to: "users#search_user"
controllers/users_controller.rb
def search_user
#users = User.search(params[:name], params[:age], params[:skin], params[:weight], params[:height]) // search name or age
// you can use byebug to check #users
end
models/user.rb
def self.search(name, age, skin, weight, height)
if name.blank? & age.blank? & skin.blank? & weight.blank? & hight.blank?
all
else
where('name LIKE ? OR age LIKE ? OR skin LIKE ? OR weight LIKE ? OR height LIKE ?', "%#{name}%", "%#{age}%", "%#{skin}%", "%#{weight}%", "%#{height}%")
end
end
=> This is my way which i used. Hope to help you.
I have a problem with the mass-assignment and strong parameters. In my model I have several attributes, that are represented through a column in my mysql database. I also have a field, that isn't. I just need it to calculate a value. I don't want to store it in my database.
In my controller I defined the strong parameters:
def timeslots_params
params.require(:timeslot).permit(:employee_id, :dienstplan_id, :start_date, :start_time)
end
But when I'm trying to access the start_time attribute in my controller, I'm getting the
undefined method `start_time' for #<Timeslot:0x007fff2d5d8070> error.
The other defined parameters with db columns are present and filled with values. Do I missunderstand the strong parameters and have to define something else?
EDIT: Here is the code, where I call the timeslots_params:
def create
#e = Timeslot.new(timeslots_params)
#e.start_date = #e.start_date.to_s + " " + #e.start_time.to_s
if #e.save
current_user.timeslots << #e
respond_to do |format|
format.json { render :json => #e }
end
end
end
In your Model provide access to the start_time field:
attr_accessor :start_time
If you only need read access:
attr_reader :start_time
Please, permit only the params you expect your user send with data. If start_time is not user data for update your db, use this way:
params.require(:timeslot).permit(:employee_id, :dienstplan_id, :start_date)
Strong parameters prevents save data that user sends and you don't want he/she update.
If you use :start_time, it must be defined at your model.
Ops, I've seen your update:
#e.start_date = #e.start_date.to_s + " " + #e.start_time.to_s
If you send :start_time to an Timeslot instance them start_time must be a method of Timeslot model. Defined by rails if it is a db field, defined with attr_accesor or att_reader or defined by a def key on your source model.
If not #e.start_time trigger undefined method 'start_time'.
edited again:
Now, start_time is a model variable. Make sure it is send to the form in the same way that you do with the fields. By default we use an f <%= f.text_field :the_field %>. Just don't forget the f.
Now you must permit this field again, if you follow my first advice.
While Alireza's answer couldwork, you might also try defining the setter method yourself, then you can play with the variable before save.
def start_time=(time)
# use variable time to do what you want with the model
end
So I've got an edit page that has butt-load of editable fields on it...simple update...
#patient.update_attributes(params[:patient])...everything's great, except....
I've got one field out of these 20 that I need to tweak a little before it's ready for the db and it would seem I either need to do
two trips
#patient.update_attributes(params[:patient])
#patient.update_attribute( :field=>'blah')
or set them all individually
patient.update_attributes(:field1=>'asdf', :field2=>'sdfg',:field3=>'dfgh', etc...)
Am I missing a way to do this is one swoop?
What's the attribute you need to tweak? There's two ways to do this:
Either massage the params before you send them to the update_attribute method:
I'm just giving an example here if you wanted to underscore one of the values:
params[:patient][:my_tweak_attribute].gsub!(" ", "_")
#patient.update_attributes(params[:patient])
Then there's the preferred way of doing your tweaking in a before_save or before_update callback in your model:
class Patient < ActiveRecord::Base
before_update :fix_my_tweak_attribute, :if => :my_tweak_attribute_changed?
protected
def fix_my_tweak_attribute
self.my_tweak_attribute.gsub!(" ", "_")
end
end
This keeps your controller clean of code that it probably doesn't really need.
If you just need to add a new param that didn't get sent by the form you can do it in the controller like this:
params[:patient][:updated_by_id] = current_user.id
#patient.update_attributes(params[:patient])
Assuming current_user is defined for you somewhere (again, just an example)
You can create a virtual attribute for that field. Say the field is :name. You create a function in your Patient model like :
def name
self[:name] = self[:name] * 2
end
And of course, you do your things inside that function :) Instaed of self[:name], you can also use read_attribute(:name).
So basically I have a controller. something like this
def show
#user = User.find[:params[id]]
#code to show in a view
end
User has properties such as name, address, gender etc. How can I access these properties in the model? Can I overload the model accesser for name for example and replace it with my own value or concatenate something to it. Like in the show.html.erb view for this method I might want to concatenate the user's name with 'Mr.' or 'Mrs.' depending upon the gender? How is it possible?
I would hesitate to override the attributes, and instead add to the model like this:
def titled_name
"#{title} #{name}"
end
However, you can access the fields directly like this:
def name
"#{title} #{self[:name]}"
end
You can create virtual attributes within your model to represent these structures.
There is a railscast on this very subject but in summary you can do something like this in your model
def full_name
[first_name, last_name].join(' ')
end
def full_name=(name)
split = name.split(' ', 2)
self.first_name = split.first
self.last_name = split.last
end
If you wish to explicitly change the value of an attribute when reading or writing then you can use the read_attribute or write_attribute methods. (Although I believe that these may be deprecated).
These work by replacing the accessor method of the attribute with your own. As an example, a branch identifier field can be entered as either xxxxxx or xx-xx-xx. So you can change your branch_identifier= method to remove the hyphens when the data is stored in the database. This can be achieved like so
def branch_identifier=(value)
write_attribute(:branch_identifier, value.gsub(/-/, '')) unless value.blank?
end
If you are accessing data stored directly in the database you can do this in you view:
<%= #user.firstname %>
<%= #user.gender %>
etc.
If you need to build custom representations of the data, then you will either need to create helpers, or extend the model (as above).
I tend to use helper methods added to the model for things like that:
def formatted_name
"#{title} #{first_name} #{last_name}"
end
(Edit previous post. Looked back at my code and realized helpers are supposed to be for presentation-related (mark-up) stuff only.)
(Edit again to remove left-over parameter... Geez, not enough coffee this morning.)
(Edit again to replace $ with #... Perhaps I should just remove this one huh?)
You can easily overload the attributes as you suggest.
i.e. if name is a field in the users database table, you can do:
def name
"#{title} #{read_attribute[:name]}"
end
The read_attribute function will return the database column value for the field.
Caveat: I am not sure this is a good idea. If you want a method that displays model data in a modified way, I would be tempted not to overload the default methods, and call them something different - this will avoid a certain level of obfuscation.
Documentation here: http://api.rubyonrails.org/classes/ActiveRecord/Base.html (under 'Overwriting default accessors')
in http://api.rubyonrails.org/classes/ActionController/Base.html
search for
Overwriting default accessors
I'm working on a Rails app that sends data through a form. I want to modify some of the "parameters" of the form after the form sends, but before it is processed.
What I have right now
{"commit"=>"Create",
"authenticity_token"=>"0000000000000000000000000"
"page"=>{
"body"=>"TEST",
"link_attributes"=>[
{"action"=>"Foo"},
{"action"=>"Bar"},
{"action"=>"Test"},
{"action"=>"Blah"}
]
}
}
What I want
{"commit"=>"Create",
"authenticity_token"=>"0000000000000000000000000"
"page"=>{
"body"=>"TEST",
"link_attributes"=>[
{"action"=>"Foo",
"source_id"=>1},
{"action"=>"Bar",
"source_id"=>1},
{"action"=>"Test",
"source_id"=>1},
{"action"=>"Blah",
"source_id"=>1},
]
}
}
Is this feasible? Basically, I'm trying to submit two types of data at once ("page" and "link"), and assign the "source_id" of the "links" to the "id" of the "page."
Before it's submitted to the database you can write code in the controller that will take the parameters and append different information before saving. For example:
FooController < ApplicationController
def update
params[:page] ||= {}
params[:page][:link_attributes] ||= []
params[:page][:link_attriubtes].each { |h| h[:source_id] ||= '1' }
Page.create(params[:page])
end
end
Edit params before you use strong params
Ok, so (reviving this old question) I had a lot of trouble with this, I wanted to modify a param before it reached the model (and keep strong params). I finally figured it out, here's the basics:
def update
sanitize_my_stuff
#my_thing.update(my_things_params)
end
private
def sanitize_my_stuff
params[:my_thing][:my_nested_attributes][:foo] = "hello"
end
def my_things_params
params.permit(etc etc)
end
You should also probably look at callbacks, specifically before_validate (if you're using validations), before_save, or before_create.
It's hard to give you a specific example of how to use them without knowing how you're saving the data, but it would probably look very similar to the example that Gaius gave.