Access params with wildcard in Rails - ruby-on-rails

At the moment I have a form_tag which contains inputs and puts these inputs into parameters.
I want to be able to loop over them in the controller action.
I've tried getting all params excluding all the usual params (action, controller, model name etc.) and then using a wildcard like params[:prop*].
Here is the offending form inputs:
%input{:name => "userEmails", :id =>"userEmails", :type => "hidden", :value => ""}
-#all_properties.each do |prop|
%input{:name => "prop"+prop.name+"checkbox", :type => "checkbox", :id => "prop"+prop.name+"checkbox"}
#{prop.name}
%input{:name => "prop"+prop.name, :type => "text", :id => "prop"+prop.name}
These show up in params like {"propProperty1checkbox"=>"on", "propProperty1" => "testing", "propAnotherPropertycheckbox" => "on", "propAnotherProperty" => "another test value"} etc.
I'm unsure how to access these as the names of the properties can change and so need to be accessed abstractly.

You can use #select on params hash to filter only the params that are interesting for you:
params = {"user_id"=>1,
"propProperty1checkbox"=>"on",
"propProperty1"=>"testing",
"propAnotherPropertycheckbox"=>"on",
"propAnotherProperty"=>"another test value"
}
params.to_h.select{|key, value| key =~ /^prop/}
#=> {"propProperty1checkbox"=>"on",
#"propProperty1"=>"testing",
#"propAnotherPropertycheckbox"=>"on",
#"propAnotherProperty"=>"another test value"}
EDIT
Example from the comment:
[13] pry(main)> {"utf8"=>"✓", "_method"=>"put", "authenticity_token"=>"xxxxx", "userEmails"=>"teste#test.com,test2#test.com,test4#test.com,fasd#gmail.com", "propProperty1checkbox"=>"on", "propProperty1"=>"3", "propAnotherPropertycheckbox"=>"on", "propAnotherProperty"=>"4", "commit"=>"Submit", "Application"=>"8", "Company"=>"1" }.to_h.select{|k, v| k =~ /^prop/}
=> {"propProperty1checkbox"=>"on",
"propProperty1"=>"3",
"propAnotherPropertycheckbox"=>"on",
"propAnotherProperty"=>"4"}

You can try something like:
input(name: "props[#{pro_name}][checkbox]"...)
input(name: "props[#{pro_name}][text]"...)
Then, in your controller:
def method
props = params[:props]
props.each do |property_name, values|
chk = values[:checkbox]
text = values[:text]
end
end

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
)
)

Ruby on Rails Model creation string not converted to integer

Here is my code:
base_release_id column in release db is integer type
form.html.haml
= form_for #release do |f|
= f.label :name
%br
= f.text_field :name
....
= f.label :base_release_id
%br
= f.select :base_release_id, options_from_collection_for_select(conditionsPlusBlankOrderBy(Release),"id","name",#release.base_release_id)
= f.submit
releases_controller.rb
def create
ap params
#release = Release.new(params[:release])
ap #release
...
end
I was going to create a new release including its name , base release id etc.
I was using 2 "ap" to trace the release object. strange thing happen. See my log below:
{
"utf8" => "â",
"authenticity_token" => "8HdDlC3jJxYvq+8tUh/cut5ibHxjIF6L2CzAFORlNBg=",
"release" => {
"name" => "e",
"code" => "e",
"base_release_id" => "2"
},
"commit" => "Create Release",
"action" => "create",
"controller" => "releases"
}
#<Release:0x000000190f06b8> {
:id => nil,
:name => "e",
:code => "e",
:base_release_id => nil,
}
Processing by ReleasesController#create as HTML
Parameters: {"utf8"=>"â", "authenticity_token"=>"8HdDlC3jJxYvq+8tUh/cut5ibHxjIF6L2CzAFORlNBg=", "release"=>{"name"=>"e", "code"=>"e", "base_release_id"=>"2"}, "commit"=>"Create Release"}
Not sure why base_release_id lost, name and code is working.
I have the similar code works in other page, in which case parame string value don't parsed to model integer?
it works if i added the datatype convertion as below:
def create
ap params
#release = Release.new(params[:release])
#release.base_release_id = params[:release][:base_release_id].to_i if params[:release][:base_release_id]
ap #release
...
end
Please help and thank you in advance.
found why.
in my model release.rb, i'v defined "attr_accessible :id, :name, :code, :as => :tmp_use". Then it accept id, name and code only. After i added :base_release_id, it works.
not sure how :as => :tmp_use work. I suppose default all variable can be accessed. In some places, i was using
Release.new("id"=>row[:id],"name"=>row[:name],"code"=>row[:code], :as => :tmp_use)
Some places i don't want to do it i want to all columns be accessable.
No sure how.
Thank you Ivan anyway.

Rails: Setting class and data-tag of an HTML attribute with a single rails method

I'm currently working on a tour interface that guides new users around my site. I have a Tour model that has many TourStops, each of which contains information about a section of the site.
Basically, I'd like to write a function for the Tour model that -- when passed the number of a TourStop -- generates the correct class and data attribute for the HTML element it's attatched to. For example, I'd like
<%= link_to image_tag("new_button.png", tour.stop_data(1), :title => 'Add new asset'), new_asset_path %>
to call a function and return something like
def stop_data(order)
" :class => '#{tour_stops.find_by_order(order).name}',
:data => '{:order => order}'"
end
creating a link_to tag like:
<%= link_to image_tag("new_button.png", :class => 'tour_stop_1',
:data => {:order => 1}, :title => 'Add new asset'), new_asset_path %>
The above code doesn't work. Is something like this even possible? If not, what's a better approach I might take?
The image_tag accepts two parameters. A source, and a options Hash.
What you are trying to do is squeezing your return value from stop_data into this options Hash.
In order to get this to work, you first, need to return a Hash from stop_data, and second, make sure you pass only two arguments to image_tag - the source, and the options.
First:
def stop_data(order)
{
:class => tour_stops.find_by_order(order).name,
:data => { :order => order } # you may need order.to_json
}
end
Second:
link_to image_tag("new_button.png", tour.stop_data(1), :title => "Add new asset"), new_asset_path
This looks like it will work, but it won't, since your'e passing three parameters to image_tag.
When you do the following:
image_tag("new_button.png", :class => "tour_stop_1", :data => { :order => 1 }, :title => "Add new asset")
It looks like you're passing even 4 parameters to image_tag, but in fact they are only two. In Ruby, when the last parameter of a method is a Hash, you don't need to wrap the Hash key/value pairs in curly braces ({}), so the example above is essentially the same as
image_tag("new_button.png", { :class => "tour_stop_1", :data => { :order => 1 }, :title => "Add new asset" })
Now, to get your helper to work with image_tag, you need to merge the options, so they become only one Hash.
link_to image_tag("new_button.png", tour.stop_data(1).merge(:title => "Add new asset")), new_asset_path
Again, we're omitting the curly braces when calling merge, because it's only (and therefore last) parameter is a Hash. The outcome is the same as:
tour.stop_data(1).merge({ :title => "Add new asset" })

What is the ActiveScaffold syntax for a 'has_many' relation link in list view if placed in the helper?

A 'product' has many 'parallel_products':
class Product < ActiveRecord::Base
has_many :parallel_products, :class_name => "Product", :foreign_key => "master_product_id"
end
In the controller I add the 'parallel_products' column to the list view:
class ProductsController < ApplicationController
active_scaffold :product do |config|
config.list.columns = [ :parallel_products ]
end
end
This gives me a ActiveScaffold generated link in the list view to view, create and edit parallel products of the selected product.
So far so good.
Now, I want to specify this 'parallel_products' link in the helper instead. No changes to the link itself, it should be exactly as the ActiveScaffold generated link. The reason is that I need to add a condition, so that the link is only shown under certain circumstances.
The ActiveScaffold generated link looks like this in the log:
Started GET "/products?assoc_id=6&association=parallel_products&eid=products_6_parallel_products&parent_scaffold=products&adapter=_list_inline_adapter" for 172.16.99.11 at 2012-03-05 09:37:45 +0100
Processing by ProductsController#index as JS
Parameters: {"assoc_id"=>"6", "association"=>"parallel_products", "eid"=>"products_6_parallel_products", "parent_scaffold"=>"products", "adapter"=>"_list_inline_adapter"}
My best proposal for the ActiveScaffold has_many relation link in the helper is:
link_to("link text", :controller => "products", :assoc_id => record.id, :association => "parallel_products", :eid => "products_#{record.id}_parallel_products", :parent_scaffold => "products", :adapter => "_list_inline_adapter")
This gives me in the log:
Started GET "/products?adapter=_list_inline_adapter&assoc_id=6&association=parallel_products&eid=products_6_parallel_products&parent_scaffold=products" for 172.16.99.11 at 2012-03-05 09:39:38 +0100
Processing by ProductsController#index as HTML
Parameters: {"adapter"=>"_list_inline_adapter", "assoc_id"=>"6", "association"=>"parallel_products", "eid"=>"products_6_parallel_products", "parent_scaffold"=>"products"}
My link does not work, but it seems to be very close. Only difference is that the generated link state 'ProductsController#index as JS' and my syntax state 'ProductsController#index as HTML'.
What is the correct ActiveScaffold syntax for making a 'has_many' relation list view link in the helper?
Thanks to Sergio Cambra for helping to solve this.
This is the syntax for a 'has_many' association link if placed in the helper:
link_to("link text", {:controller => "products", :association => "parallel_products",
:parent_scaffold => "products", :product_id => record.id}, :class => 'index as_action',
:id => "as_products-index-parallel_products-#{record.id}-link",
:remote => true, :data => {:position => :after, :action => 'index'})
To answer the question in full, this is how it can be implemented to exactly replace the autogenerated AS association link:
def parallel_products_column(record)
if product.parallel_products.blank?
link_text = "-"
css_class = "index as_action empty"
else
link_text = product.parallel_products[0...3].map{ |p| p.name }.join(", ")
if product.parallel_products.length > 3
link_text += ", … (#{product.parallel_products.length})"
end
css_class = "index as_action"
end
link_to(link_text.html_safe, {:controller => "products", :association => "parallel_products",
:parent_scaffold => "products", :product_id => record.id}, :class => css_class,
:id => "as_products-index-parallel_products-#{record.id}-link",
:remote => true, :data => {:position => :after, :action => 'index'})
end
You will need a small 'hack' for the css 'empty' class, example:
.active-scaffold a.empty {
display: block;
text-align: center;
}
Note:
This is for Rails/AS 3.1 or newer.

On the fly tags generation for XML Builders

I have a hash like,
object = { :type => 'book', :name => 'RoR', :price => 33 }
OR
object = { :type => 'wig', :name => 'Elvis-Style', :price => 40, :color => 'black' }
The problem is that keys in above hash may be different all the time or even increase and decrease depending upon the object type.
What I want to do generate XML for above hashes using Xml::Builder. The XML tags are decided by the keys in the hash and text inside a tag is value corresponding that key.
I can use eval to do this like below. However, I think there must be a better way to do it.
object.each do |key, text|
eval("xml.#{key.to_s} do
#{text}
end
")
end
#object.each do |k, v|
xml.tag!(k.to_s, v)
end
Rails supports to_xml on Hash classes.
hash = { :type => 'book', :name => 'RoR', :price => 33 }
hash.to_xml
# Returns
# <?xml version=\"1.0\" encoding=\"UTF-8\"?>
# <hash>
# <type>book</type>
# <name>RoR</name>
# <price type=\"integer\">33</price>
# </hash>
If you want to skip the types then:
hash.to_xml(:skip_types => true)
If you want to give a different root then:
hash.to_xml(:root => 'options')
This one worked.
#object.each do |k, v|
xml.tag!(k.to_s, v)
end
out << "<#{key}>#{html_escape(value)}</#{key}>"

Resources