Passing params in a helper - ruby-on-rails

I have, on my Miniature model view page the following code
<%= content_setmini_links_with_quantity(#miniature) %>
It refers to this miniatures_helper method
def content_setmini_links_with_quantity(miniature)
miniature.reverse_contents.map{|content| content_setmini_link_with_quantity(content)}.join(' ').html_safe
end
Which in turn references this miniatures_helper method
def content_setmini_link_with_quantity(content)
string = (tag "td"), (link_to top_pic(content.setmini_id), content.setmini), (link_to content.setmini.name, content.setmini)
string << " x#{content.quantity}" if content.quantity.present?
return string
end
This is supposed to reference the final miniatures_helper method
def top_pic
#miniature = Miniature.find(params[:setmini_id])
if #miniature.collections.first.photo != nil
image_tag(#miniature.collections.first.photo.url(:icon), :retina => true, :class => "curvediconminiset")
else
image_tag("https://system/stock/blank.gif", :retina => true, :class => "curvediconminiset")
end
end
but I can't work out how to call top_pic correctly.
As far as I can see in content_setmini_link_with_quantity(content) the only param available is content. Content.setmini_id is the param I want to use to find the #miniature to display but I can't get it to work.
Any help much appreciated.

You are calling
top_pic(content.setmini_id)
But your top_pic method definition does not have a parameter defined.
Change the definition and first line of top_pic to
def top_pic(setmini_id)
#miniature = Miniature.find(setmini_id)
and forget about using params in a helper.

Related

Rails: understanding custom form helper

new.html.erb
<%= form_for #star do |f|%>
<%= star_radio(f, true)%>
<% end %>
stars_helper.rb
module StarHelper
def star_radio(form, status)
form.label "star_#{status}", class: 'radio-inline' do
form.radio_button(:star, status) + i18n_star(status)
end
end
def i18n_star (status)
I18n.t("activerecord.attributes.star.is_sun.#{status}")
end
end
I saw a piece of code like above.
I am not familiar with custom form helper.
Could you let me know why we can use form.radio_button(:star, status) + i18n_star(status) inside a block and why we can use '+' to add text on radio buttons.
I will be appreciated if you could tell me where I can go to learn this.
form.radio_button helper returns a string and I18n.t too returns a string. So, you can concatenate them.
More details how form tag is generated
This is a code of radio_button:
https://github.com/casunlight/rails/blob/master/actionview/lib/action_view/helpers/form_helper.rb
def radio_button(object_name, method, tag_value, options = {})
Tags::RadioButton.new(object_name, method, self, tag_value, options).render
end
Look at implementation of render method
https://github.com/casunlight/rails/blob/master/actionview/lib/action_view/helpers/tags/radio_button.rb#L20
def render
options = #options.stringify_keys
options["type"] = "radio"
options["value"] = #tag_value
options["checked"] = "checked" if input_checked?(object, options)
add_default_name_and_id_for_value(#tag_value, options)
tag("input", options)
end
Tag helper generate html tag and return his as html safed string:
https://github.com/casunlight/rails/blob/master/actionview/lib/action_view/helpers/tag_helper.rb#L67
def tag(name, options = nil, open = false, escape = true)
"<#{name}#{tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe
end

Rails API Does not split Json

Weird problem. If the class at the bottom was a module, split the Json without problems, if it was only methods, also works, but the problem is.. when it is a class, it does not split the Json anymore, and returns an empty array.. however, if being a class, I do a puts the object, it actually puts it..
Any thoughts about why? How can I fix it?
I have this controller:
def index
begin
call_employee_work_locations_api
rescue => ex
render :json => {"service unavailable": "0001" }, :status => :service_unavailable
end
end
I have this service:
def call_employee_work_locations_api
auth = {:username=>ENV["USERNAME"], :password=>ENV["PASSWORD"]}
employee_locations = HTTParty.get(employee_work_Location_url , :basic_auth => auth)
#serialize_work_location(employee_locations)
serializer = EmployeeSerializer.new
serializer.serialize_work_location(employee_locations)
end
I have this builder:
json.array!(#top_locations) do |location|
json.extract! location, :name, :description, :latitude, :longitude
end
I have this class:
class EmployeeSerializer
def serialize_work_location(employee_locations)
employee_locations= JSON.parse(employee_locations)
locations=[]
employee_locations["work_locations"].each do |attributes|
location = Location.new(attributes["latitude"],attributes["longitude"],attributes["description"],attributes["name"])
locations.push(location)
end
employee_locations_selector(locations)
end
def top_office_location_selector(locations, city)
top_locations=[]
locations.each do |office|
if office.name == city[0] then top_locations.push(office) end
if office.name == city[1] then top_locations.push(office) end
end
#top_locations = top_locations
p #top_locations <--- it prints the object perfectly, but does not pass to the view, I get an empty array instead.
end
def employee_locations_selector(locations)
city = locations.each_with_object(Hash.new(0)) { |locations, counts| counts[locations.name] += 1 }.max_by{|k,v| v}
top_office_location_selector(locations, city)
end
end
The instance variable #top_locations is being set within the scope of the EmployeeSerializer class, not your controller. As such it's just a normal instance variable and so Rails knows nothing about it. You can assign the return value of #top_office_location_selector to an instance variable in the controller and it should work.
On a side note, the code would be cleaned up a lot by using #map over #each.

Refactoring a hash to Object

I have a method that return a Hash and then I write the entries of hash in xml file. Iwant to convert this Hash to an object to store the entry and then write it to xml file...
My current code is like this
def entry(city)
{
:loc => ActionController::Integration::Session.new.url_for(:controller => 'cities', :action => 'show', :city_name => city.name, :host => #country_host.value),
:changefreq => 0.8,
:priority => 'monthly',
:lastmod => city.updated_at
}
end
The write_entry method is inside my writer class that writes this entry to xml file
def write_entry(entry)
url = Nokogiri::XML::Node.new( "url" , #xml_document )
%w{loc changefreq priority lastmod}.each do |node|
url << Nokogiri::XML::Node.new( node, #xml_document ).tap do |n|
n.content = entry[ node.to_sym ]
end
end
url.to_xml
end
Thanks
I might be way off here, but it seems like what you're trying to do is something like this:
First, figure out what makes sense as a class name for your new object. I'm going with Entry, because that's the name of your method:
class Entry
end
Then take all the "properties" of your hash and make them reader methods on the object:
class Entry
attr_reader :loc, :action, :changefreq, :priority, :lastmod
end
Next you need to decide how this object will be initialized. It seems like you will need both the city and #country_host for this:
class Entry
attr_reader :loc, :action, :changefreq, :priority, :last mod
def initialize(city, country_host_value)
#loc = ActionController::Integration::Session.new.url_for(:controller => 'cities', :action => 'show', :city_name => city.name, :host => country_host_value)
#changefreq = 0.8 # might actually want to just make this a constant
#priority = 'monthly' # another constant here???
#lastmod = city.updated_at
end
end
Finally add your XML builder method to the class:
class Entry
attr_reader :loc, :action, :changefreq, :priority, :last mod
def initialize(city, country_host_value)
#loc = ActionController::Integration::Session.new.url_for(:controller => 'cities', :action => 'show', :city_name => city.name, :host => country_host_value)
#changefreq = 0.8 # might actually want to just make this a constant
#priority = 'monthly' # another constant here???
#lastmod = city.updated_at
end
def write_entry_to_xml(xml_document)
url = Nokogiri::XML::Node.new( "url" , xml_document )
%w{loc changefreq priority lastmod}.each do |node|
url << Nokogiri::XML::Node.new( node, xml_document ).tap do |n|
n.content = send(node)
end
end
url.to_xml
end
end
Now that your hash has been refactored, you can update your other class(es) to use the new object:
class WhateverClassThisIs
def entry(city)
Entry.new(city, #country_host.value)
end
end
It's not clear how the XML writer method is being called, but you would need to update that as well to use the new write_entry_to_xml method, passing in the xml document as an argument.

Rails form params changing in controller

I have a form:
<%= form_for(:report_main, :url => {:action => 'exporttoxiccreate'}) do |f| %>
<%= collection_select(:waste, :code, Waste.find_all_by_istoxic(false), :id, :code, :include_blank => '') %>
<%= f.check_box(:q_pripadnost) %>
<%= f.text_field(:amount) %>
<% end %>
and this code in controller:
def exporttoxiccreate
#report = ReportMain.new
#reportexport = ReportExport.new
#reportparam = params[:report_main]
#report.waste_id = #reportparam.waste.code
#report.amount = #reportparam.amount
if #report.save
#reportexport.report_main_id = #report.id
else
redirect_to(:action => 'exporttoxicnew')
end
#reportexport.q_pripadnost = #reportparam.q_pripadnost
if #reportexport.save
redirect_to(:action => 'show', :id => #reportexport.id)
else
redirect_to(:action => 'exporttoxicnew')
end
end
I want to save in two tables, in two objects data from this form, and I need to separate params to manipulate with. I tried with this:
#reportexport.q_pripadnost = #reportparam.q_pripadnost
I want to set q_pripadnost field in #reportexport with some value from param.
Where I make mistake?
When you get params from a form in Rails, it comes in the form of a hash. For example:
params[:report_main][:waste]
params[:report_main][:amount]
So when you call #reportparam = params[:report_main], you are setting #reportparam to a hash, but then you are trying to use it later like an object. For example, instead of #reportparam.q_pripadnost, use #reportparam[:q_pripadnost].
You can take a closer look at your variable by temporarily changing your action to show a text version of the variable, for example:
def exporttoxiccreate
#reportparam = params[:report_main]
render :text => #reportparam.to_yaml
end

How to add additional params to a button_to form?

I want to have a Submit button. It updates one field on the submission; submission.state = :submitted
Now, I could make a custom route and a custom action and just post to that. But that seems really heavy-handed. Especially since I'll also have a reject button and possibly more. Needing a custom route & action for each of those seems downright silly to me.
It would be much nicer if I could do something like
button_to "Submit", submission_url(submission), :method => :put, :submission => { :state => :submitted }
Which would post to the submission's update method and update only the desired field.
But that doesn't work. How can I make it work? Or do you have a better idea of how to do this?
The pull request mentioned by #AugustinRiedinger has been merged and is now available as of Rails 4.1.0. Now just add the params option:
params: { state: :submitted }
It's not as concise, but without extending Rails, this will get me by:
= form_for submission, :html => { :class => "button_to" } do |f|
= f.hidden_field :state, :value => :submitted
= f.submit "Submit", :class => "link"
Add params:{} at the end, it will generate hidden_field
<%= button_to user.name, user, class:"btn btn-default", style:"", method: :patch, remote: true, params: { a_field: false, an_other_field:"a new value" } %>
I have something similar that works:
button_to "Submit", submission_url(submission, :submission => { :state => :submitted }), :method => :put
So, as from this rails pull request : https://github.com/rails/rails/pull/10471
Here is what you can do to have your custom button_to.
In application_helper.rb, add these lines:
module ApplicationHelper
// Unfortunately these 2 methods need to be redefined. I don't know how I could access the original ones.
def token_tag(token=nil)
if token != false && protect_against_forgery?
token ||= form_authenticity_token
tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token)
else
''
end
end
def method_tag(method)
tag('input', type: 'hidden', name: '_method', value: method.to_s)
end
def button_to_with_params(name = nil, options = nil, html_options = nil, &block)
html_options, options = options, name if block_given?
options ||= {}
html_options ||= {}
html_options = html_options.stringify_keys
convert_boolean_attributes!(html_options, %w(disabled))
url = options.is_a?(String) ? options : url_for(options)
remote = html_options.delete('remote')
params = html_options.delete('params') { Hash.new }
method = html_options.delete('method').to_s
method_tag = %w{patch put delete}.include?(method) ? method_tag(method) : ''.html_safe
form_method = method == 'get' ? 'get' : 'post'
form_options = html_options.delete('form') || {}
form_options[:class] ||= html_options.delete('form_class') || 'button_to'
form_options.merge!(method: form_method, action: url)
form_options.merge!("data-remote" => "true") if remote
request_token_tag = form_method == 'post' ? token_tag : ''
html_options = convert_options_to_data_attributes(options, html_options)
html_options['type'] = 'submit'
button = if block_given?
content_tag('button', html_options, &block)
else
html_options['value'] = name || url
tag('input', html_options)
end
inner_tags = method_tag.safe_concat(button).safe_concat(request_token_tag)
params.each do |name, value|
inner_tags.safe_concat tag(:input, type: "hidden", name: name, value: value.to_param)
end
content_tag('form', content_tag('div', inner_tags), form_options)
end
end
And to use it:
= button_to_with_params 'Awesome button', awesome_action_path, method: :put, :params => {:my_param => 'my_value'}
Enjoy! Have fun Railing!
If I read things correctly what you are effectively wanting to do something specific when a standard rails form is submitted in the standard way.
Notice that when a form is submitted using e.g.
f.submit "Save Changes"
then
params[:commit] = "Save Changes"
The GOOD thing about this is that it can allow you to do some appropriate branching in the controllers update action.
The BAD thing is that it's brittle. If one day you or someone else decides to change the button text, things break.. which is bad.
K
As of Rails 3.2.1 you can add additional params to the :html_options hash using the :form key.
http://apidock.com/rails/v3.2.1/ActionView/Helpers/UrlHelper/button_to
This did not exist prior to 3.2.1 so the more verbose solution of declaring a form with hidden attributes was required.

Resources