I try to pass params as a hash in url with postman like this
http://localhost:3000/api/v1/bill?album=3&song=4&song=7&album=6
I use this code to get param
def param_hash
params.permit(:album, :song)
end
and print this value param_hash.to_h
This is a value i want {"album"=3, "song"=>4, "album"=>6, "song"=>7}
But in reality that's what i got {"album"=>6, "song"=>7} , just have only 1 hash in last.
Is there anyway to take all hash value in url?
def param_hash
params.permit(album: [], song: [])
end
http://localhost:3000/api/v1/bill?album[]=3&song[]=4&song[]=7&album[]=6
According to https://github.com/rails/strong_parameters
The permitted scalar types are String, Symbol, NilClass, Numeric, TrueClass, FalseClass, Date, Time, DateTime, StringIO, IO, ActionDispatch::Http::UploadedFile and Rack::Test::UploadedFile.
To declare that the value in params must be an array of permitted scalar values map the key to an empty array:
params.permit(:id => [])
http://localhost:3000/api/v1/bill?data={album: 3,song: 4,song: 7,album: 6 }
Use the above logic and permit the 'data' object.
Related
I have a method do_stuff that takes a string as a value. However, an array of two strings is occasionally passed in. In this situation, I need to convert the array to a single string (without commas). So for example, ["hello", "world"] should become "hello world".
So, if value = array, join the two strings, otherwise leave it alone.
The following line I have does what I want, but I am struggling with actually "saving" the value before passing it to the method do_other_stuff.
def do_stuff(value)
value.join("") if value.is_a? Array
do_other_stuff(value)
end
So I think i am close, but what would be the best way to ensure value is manipulated before passing it to do_other_stuff ?
join does not change your object, you're wasting its return value
value = value.join if value.is_a? Array
Note that "" is the default for the join parameter, so I got rid of it
Replace
value.join("") if value.is_a? Array
With
value = value.join("") if value.is_a? Array
Basically you need to reassign result back to value
Use duck typing instead of checking the class:
def do_stuff(value)
do_other_stuff(value.try(:join, '') || value)
end
.try is from ActiveSupport and will return nil if the object does not respond to the method. In plain old ruby you would write this as:
def do_stuff(value)
do_other_stuff(value.respond_to?(:join) ? value.join("") : value)
end
I need to create a method that dynamically filters a model by a column. It needs to receive the column that I want to filter by (called attr_name), an operator as a string, and the value as a string.
I need to first cast the string value to the database column type so I can then do the sql query.
scope :filtered_by_attribute, (lambda do |attr_name, operator, value|
comparing_value = Customer.attribute_types[attr_name].cast(value)
casting_error = !value.nil? && comparing_value.nil?
raise I18n.t('api.errors.unaplicable_customer_scope') if casting_error
sql_query = sanitize_sql("#{attr_name} #{operator} ?")
where(sql_query, comparing_value)
end)
The problem above is when it comes to enums. Enums are integers on the db but when I perform the casting it will return the same string value since for rails it is a string. Then, in the where query, it explodes since in the database it's comparing an integer column with a string.
Do you know how I cast a string value to match the type of a column in the database?
Thank you!
The cast method casts a value from user input when it is assigned to an instance. In the case of enum when you assign a string value it remains a string value. It is converted to an integer only when it is persisted in DB.
class Order < ActiveRecord::Base
enum status: {confirmed: 1, cancelled: 2}
end
# this is where the `cast` method is called
#order.status = "cancelled"
# still a string since the `cast` method didn't do anything.
#order.status # => "cancelled"
What you really need is the serialize method. It casts a value from a ruby type to a type that the database knows how to understand.
Order.attribute_types["status"].serialize("cancelled") # => 2
Is there a way to require an array when using strong parameters in Rails 4?
> params = ActionController::Parameters.new(contacts: [])
=> {"contacts"=>[]}
> params.require(:contacts)
ActionController::ParameterMissing: param not found: contacts
As Steve Wilhelm noted, it works if the array is non-empty. It only fails on your example because the contacts array is empty. But that's usually the desired behavior.
If you don't care what's in the array, just use permit.
That said, I'd imagine the most common case is that you want an array of hashes with known keys. I would do that this way:
# Returns an array of contacts after checking the params shape
# Use instead of params[:contacts]
def contacts_params
params.permit(contacts: %i(id name phone address))
params.require(:contacts)
end
It appears you can have arrays of Scalars, This works
> params = ActionController::Parameters.new(contacts: [nil])
=> {"contacts"=>[nil]}
> params.require(:contacts)
=> [nil]
> params = ActionController::Parameters.new(contacts: [1])
=> {"contacts"=>[1]}
> params.require(:contacts)
=> [1]
Here is the description from documentation
The permitted scalar types are String, Symbol, NilClass, Numeric, TrueClass, FalseClass, Date, Time, DateTime, StringIO, IO, ActionDispatch::Http::UploadedFile and Rack::Test::UploadedFile.
To declare that the value in params must be an array of permitted scalar values map the key to an empty array:
params.permit(id: [])
Have you tried this
params.permit(contacts: []).require(:contacts)
I'm trying to build a generator in rails but I'm getting stuck at trying to access an existing model's parameters. Basically I want to do something like this:
# user is a model the has the parameters "id: integer, name: string, and email: string"
User.parameters.each do |parameter|
# do something with id, name, email
parameter.key
# do something with integer, string, string
parameter.value
end
Any ideas?
I think what you want is this
User.columns_hash.each do |key, value|
key
value.type
end
value.type will give you the type as a symbol. You can convert it to a string if you want it as a string
I think you are looking for attributes, rather than parameters.
user = User.first
user.attributes.each do |key, value|
# do something here with keys and values
puts key if key
puts value if value
end
Notice I'm grabbing an actual instance of the model as well as checking for nils (the if key/ if value part)
Got it! Need to use columns_hash like this:
Event.columns_hash.each {|k,v| puts "#{k} => #{v.type}"}
Credit to Getting types of the attributes in an ActiveRecord object
My code looks like this:
hash = MyModel.count(:group => 'id', :conditions => 'bla = "bla"')
The returned Hash has keys that are strings. I want them to be ints. I know it would be possible to convert the Hash manually using something like a map construct.
Edit:
Thanks for the responses. Have realised it was a json conversion process that was turning the ids into Strings and rails does in fact use the Fixnum as one might expect.
hash = MyModel.count(group: 'id', conditions: 'bla = "bla"')
should have Fixnum keys by default since id is an instance of Fixnum.
What happens is that ActiveRecord always fetch result as strings and then Rails takes care of converting them to other datatypes according to the type of the database column (we say that they are typecast).
So it's maybe a Rails bug or the 'id' column is not set as integer(which would be surprising).
If you can't fix it, convert them manually:
hash.each_with_object({}) do |(key, value), hash|
hash[key.to_i] = value
end
When I use your code I get integer keys (rails 3.07), what's the column type of id?
If you want to do it manually:
new_hash = hash.inject({}){|h,a| h[a.first.to_i] = a.last; h}
new_hash = Hash[hash.map { |k, v| [k.to_i, v] }