hidden field passes all params as strings - ruby-on-rails

I have a controller called "Questions" with two actions, "practice" and "grade" both are get routes, the practice view renders a small sample of of Questions and uses forms to get user answers using submit to get the "grade path"
to grade it, I need the record objects to be passed as an array, but when passed using the hidden field I get the reference numbers as strings and not the actual object. how do i get the object so I can call question_object.answer
controllers/questions.rb
def practice
#questions = Questions.find(params[:id])
#sample_array = #questions.multiple_choices.sample(params[:number_of_multiple_choices].to_i)
#sample_array += #questions.true_falses.sample(params[:number_of_true_falses].to_i)
#user_answers = Array.new(#questions.size, 1)
end
def grade
#questions = Questions.find(params[:id])
#sample_array = params[:sample_array]
#array_answers = # create array based on sample_array's answers
#user_answers = params[:user_answers].split(' ')
#user_answers = #user_answers.map.with_index{|x,y| params[("user_answer#{y.to_s}")] }
end
views/questions/practice.html.erb # don't mind the finite number of forms its just for example.
<%= form_for :grade, :url => grade_path, method: :get do |f| %>
<%= hidden_field_tag(:sample_array, #sample_array) %>
<%= hidden_field_tag(:user_answers, #user_answers) %>
<div class="form-group">
<%= select_tag(("user_answer#{0}"), options_for_select([["a", 1],[ "b", 2],[ "c", 3],[ "d", 4]], 1), class: "form-control") %>
<%= select_tag(("user_answer#{1}"), options_for_select([["a", 1],[ "b", 2],[ "c", 3],[ "d", 4]], 1), class: "form-control") %>
<%= select_tag(("user_answer#{2}"), options_for_select([["a", 1],[ "b", 2],[ "c", 3],[ "d", 4]], 1), class: "form-control") %>
<%= select_tag(("user_answer#{3}"), options_for_select([["a", 1],[ "b", 2],[ "c", 3],[ "d", 4]], 1), class: "form-control") %>
</div>
<div id="finalscore">
<%= button_to "act_2", class:'btn btn-success' %>
</div>
<% end %>
in grade the parameters i passed are just strings like so. questions: ["#", "#", "#"]
I researched it and hidden_fields will pass query_strings and that's why im only getting strings, but I can't find any examples on how to obtain the array object to use in my grade controller action.
thanks in advance sorry for the long question I don't know how else to ask about this.

Instead of creating the arrays in your practice method, why don’t you create them in your grade method? To do this, you can instead assign #number_of_multiple_choice and #number_of_true_false in your practice method, pass those numbers in the hidden field tag, and determine your arrays in the grade action. I’m actually not sure what you’re trying to do with #user_answers in the practice action - I assume you’re just trying to create one empty answer object, but it does not appear to be used that way in the form.
controllers/questions.rb
def practice
#question = Question.find(params[:id])
#number_of_multiple_choices = params[:number_of_multiple_choices].to_i
#number_of_true_falses = params[:number_of_true_falses].to_i
end
def grade
#question = Question.find(params[:id])
#sample_array = #questions.multiple_choices.sample(params[:number_of_multiple_choices].to_i)
#sample_array += #questions.true_falses.sample(params[:number_of_true_falses].to_i)
#array_answers = # create array based on sample_array's answers
#user_answers = params[:user_answers].split(' ')
#user_answers = #user_answers.map.with_index{|x,y| params[("user_answer#{y.to_s}")] }
end
views/questions/practice.html.erb
<%= form_for :grade, :url => grade_path, method: :get do |f| %>
<%= hidden_field_tag(:number_of_multiple_choice, #number_of_multiple_choice) %>
<%= hidden_field_tag(:number_of_true_falses, #number_of_true_falses) %>
...
<% end %>
Additionally I noticed you’re saying #questions = Questions.find(params[:id]. The .find is meant to return one record but you have a) pluralized your variable indicating you want multiple questions, and b) pluralized your model, which is not standard convention. Either your model should be renamed or that will throw an error if your model is actually not pluralized.

Related

Values of a book saved from amazon have {:value=>""} around it

I'm making an application where the user can search Amazon (with Vacuum) through my application for books, then be able to record the data of the book to their library.
When you search for a book, it goes through every result and puts each in a thumbnail. In every thumbnail there is a button that opens a modal with a form with hidden tags. When the user clicks the submit button, the book's title is saved into a new book. The only problem is that the title is saved like {:value=>"the title of the book that was saved"}
Here is the part of new.html.erb which has the search box:
<%= form_tag({controller: "books", action: "new"}, method: "get", id: "search-form") do %>
<%= text_field_tag :keywords, params[:keywords], placeholder: "Search for a book", class: "form-control" %>
<% end %>
Here is the part of new.html.erb which has the hidden form:
<% #results.each do |result| %>
…
<%= form_for #book do |f|%>
<%= hidden_field_tag :title, class: 'form-control', value: result.name %>
<%= f.submit "Add book", class: "btn btn-default green-hover" %>
<% end %>
…
<% end %>
Here are the new and create actions in my controller:
def new
#book = current_user.books.build if logged_in?
# Search actions
if params[:keywords]
request = Vacuum.new
request.configure(
aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
associate_tag: 'my associate tag is here'
)
keywords = params[:keywords]
params = {
'SearchIndex' => 'Books',
'Keywords'=> keywords,
'ResponseGroup' => "ItemAttributes,Images"
}
raw_results = request.item_search(query: params)
hashed_results = raw_results.to_h
#results = []
hashed_results['ItemSearchResponse']['Items']['Item'].each do |item|
result = OpenStruct.new
result.title = item['ItemAttributes']['Title']
result.url = item['DetailPageURL']
result.image_url = item['MediumImage']['URL']
result.author = item['ItemAttributes']['Author']
result.pages = item['ItemAttributes']['NumberOfPages']
#results << result
end
end
end
def create
#book = #list.books.build(book_params)
if #book.save
flash[:success] = #book.title + "was added to your log."
redirect_to list_path(#book.list_id)
else
render 'books/new'
end
end
I tried to use gsub within book.rb to fix it, but that only changed the text within the flash message and it still saved as {:value=>"the title of the book that was saved"}.
after_create :init
private
def init
puts "Init was called!"
self.title.gsub!('{:value=>"', " ")
self.title.gsub!('"}', " ")
end
How can I change it so that it doesn't save the title with the {:value=>} around it?
I don't think the hidden field tag is right.
<%= hidden_field_tag :title, class: 'form-control', value: result.name %>
Try
<%= hidden_field_tag :title, result.name %>
Your title is being saved as a hash not a string. Use hash accessing methods:
t = title[:value]
puts t #=> "the tile of the book that was saved"

Unpermitted parameter for array with dynamic keys

I'm trying to permit an array with an arbitrary number of values, but Rails throws Unpermitted parameter: service_rates every time. I tried a lot of things (Rails 4 Unpermitted Parameters for Array, Unpermitted parameters for Dynamic Forms in Rails 4, ...) but nothing works.
The field's name is service_rates and it's column type is jsonb.
I want to create a JSON object from an arbitrary number of input fields:
<%= f.hidden_field :service_ids, value: #services.map(&:id) %>
<% #services.each do |service| %>
<tr>
<td>
<% value = #project.service_rates ? #project.service_rates["#{service.id}"]['value'] : '' %>
<%= text_field_tag "project[service_rates][#{service.id}]", value, class: 'uk-width-1-1', placeholder: 'Stundensatz' %>
</td>
</tr>
<% end %>
So my POST data looks like this:
project[service_rates][1] = 100
project[service_rates][2] = 95
project[service_rates][3] = 75
Currently service_rates is permitted via whitelisting with tap:
def project_params
params.require(:project).permit(:field1, :field2, […], :service_ids).tap do |whitelisted|
whitelisted[:service_rates] = params[:project][:service_rates]
end
end
At least, I'm building a JSON object in a private model function (which throws this error):
class Project < ActiveRecord::Base
before_save :assign_accounting_content
attr_accessor :service_ids
private
def assign_accounting_content
if self.rate_type == 'per_service'
service_rates = {}
self.service_ids.split(' ').each do |id|
service_rates["#{id}"] = {
'value': self.service_rates["#{id}"]
}
end
self.service_rates = service_rates
end
end
end
I've also tried to permit the field like that …
params.require(:project).permit(:field1, :field2, […], :service_rates => [])
… and that …
params.require(:project).permit(:field1, :field2, […], { :service_rates => [] })
… but this doesn't work either.
When I try this …
params.require(:project).permit(:field1, :field2, […], { :service_rates => [:id] })
… I get this: Unpermitted parameters: 1, 3, 2
It's not really clear what service_rates is for you. Is it the name of an association ? Or just an array of strings ?
To allow array of strings : :array => [],
To allow nested params for association : association_attributes: [:id, :_destroy, ...]
params.require(:object).permit(
:something,
:something_else,
....
# For an array (of strings) : like this (AFTER every other "normal" fields)
:service_rates => [],
# For nested params : After standard fields + array fields
service_rates_attributes: [
:id,
...
]
)
As I explained in the comments, the order matters. Your whitelisted array must appear AFTER every classic fields
EDIT
Your form should use f.fields_for for nested attributes
<%= form_for #project do |f| %>
<%= f.fields_for :service_rates do |sr| %>
<tr>
<td>
<%= sr.text_field(:value, class: 'uk-width-1-1', placeholder: 'Stundensatz' %>
</td>
</tr>
<% end %>
<% end %>

How will be the best way to render array of arrays in erb template?

I have an array [["Company Name", "Field6"], ["Email", "Field5"]]
And from that array I am creating array of fields with values:
[
[{:label=>"Company Name", :value=>"gfdgfd"}],
[{:label=>"Email", :value=>"gfdgfd#gfd.pl"}]
]
using
fields = [["Company Name", "Field6"], ["Email", "Field5"]]
# first element in array is Label and second is param id
fields_with_values = fields.collect do |field|
[
label: field[0],
value: params[field[1]]
]
end
and then I want to pass that labels and values to erb template(something like):
# template.erb
<% fields_with_values.each do |field| %>
l: <%= field.label %>
v: <%= field.value %>
<% end %>
How will be the best way to collect these fields_with_values ? Maybe I should use Object.new
Convert to a hash instead.
fields = [["Company Name", "Field6"], ["Email", "Field5"]]
fields_with_values = Hash[*fields.flatten]
# => {"Company Name"=>"Field6", "Email"=>"Field5"}
In your view, parse the hash:
<% fields_with_values.each do |label, value| %>
l: <%= label %>
v: <%= params[value.intern] %>
<% end %>
Note that this will break if your input array is uneven, ie. a key without a value.
EDIT
As mentioned in a comment below (+1), duplicate keys will not work. Fields that have the same label as another field are no good.
fields = [["Company Name", "Field6"], ["Email", "Field5"]]
# first element in array is Label and second is param id
fields_with_values = fields.collect do |label, param_id|
# It looks like there is no need for a nested array here, so just return a Hash
{
label: label,
value: params[param_id]
}
end
#=> [{:label=>"Company Name", :value=>"gfdgfd"}, {:label=>"Email", :value=>"gfdgfd#gfd.pl"}]
It looks like you are trying to use dot syntax to get values out of a Ruby Hash similar to how you would use dot syntax for a JavaScript object (e.g. field.label). Unfortunately this doesn't work for Ruby. I wish it did because it looks very clean. For the Ruby Hash you must use an index, which is a symbol in this case: field[:label]. Your ERB code will look something like this:
# template.erb
<% fields_with_values.each do |field| %>
l: <%= field[:label] %>
v: <%= field[:value] %>
<% end %>
The easy most basic way would be:
class Foo
attr_accessors :label, :value
def initialize (label, value)
#label = label
#value = value
end
end
fields_with_values = fields.map do |field|
Foo.new(field[0], params[field[1]])
end
from here on you can make it more Ruby way with splat operator or create the objects on the fly, etc. etc.
l:
v:
I would do
fields_with_values = fields.collect do |field|
{label: field[0], value: params[field[1]}
end
And in the view
<% fields_with_values.each do |field| %>
l: <%= field[:label] %>
v: <%= field[:value] %>
<% end %>
However, lets say label is a company and value is an e-mail. If you have a class like
class Company < SomethingOrNothing
attr_accessible :name, email
# methods here
end
You could do
#companies = fields.collect do |field|
Company.new(name: field[0], email: field[1])
end
And then
<% #companies.each do |company| %>
l: <%= comapny.name %>
v: <%= company.email %>
<% end %>
However, most likely creating a new class just for that is over engineering, unless you will use this class over and over in your code.

form_for, fields_for and two models

I have form that create two objects and save them to database.
I want to do next things:
save data in database (booth objects)
validate fields (I have validation in model)
and if validation fail, I want to populate fields with entered data
edit action for this form
Problems:
If I use #report I get:
Called id for nil, which would
mistakenly be 4 error
(can't find object). I have in controller, in encreate action #report = ReportMain.new and in action that render that view.
When I use :report_main (model name) it works, it save data to database, but I can't get fields populated when validation fails.
Questions:
What to do with this two models to make this to work (validation, populating fields, edit)?
Can you give me some advice if approach is wrong?
My view looks like this:
<%= form_for(#report, :url => {:action => 'encreate'}) do |f| %>
<%= render "shared/error_messages", :target => #report %>
<%= f.text_field(:amount) %>
<% fields_for #reporte do |r| %>
<%= r.check_box(:q_pripadnost) %>Pripadnost Q listi
<%= select_tag('nacinpakovanja',options_for_select([['Drveno bure', 'Drveno bure'], ['Kanister', 'Kanister'], ['Sanduk', 'Sanduk'], ['Kese', 'Kese'], ['Posude pod pritiskom', 'Posude pod pritiskom'], ['Kompozitno pakovanje', 'Kompozitno pakovanje'], ['Rasuto', 'Rasuto'], ['Ostalo', 'Ostalo']])) %>
<%= r.text_field(:ispitivanjebroj) %>
<%= r.text_field(:datumispitivanja) %>
<% end %>
<input id="datenow" name="datenow" size="30" type="text" value="<%= #date %>">
<div class="form-buttons">
<%= submit_tag("Unesi izvestaj") %>
</div>
<% end %>
encreate actin in ReportController:
def encreate
#report = ReportMain.new
#reporte = ReportE.new
#reportparam = params[:report_main]
#report.waste_id = params[:waste][:code]
#report.warehouse_id = Warehouse.find_by_user_id(current_user.id).id
#report.user_id = current_user.id
#report.company_id = current_user.company_id
#report.amount = #reportparam[:amount]
#report.isimport = false
#report.isfinished = false
#report.reportnumber = ReportMain.where(:company_id => current_user.company_id, :isimport => false).count.to_i+1
if #report.save
#reporte.report_main_id = #report.id
else
redirect_to(:action => 'exportnew')
return
end
#reporte.vrstaotpada = params[:vrstaotpada]
#reporte.nacinpakovanja = params[:nacinpakovanja]
#reporte.ispitivanjebroj = #reportparam[:ispitivanjebroj]
#reporte.datumispitivanja = #reportparam[:datumispitivanja]
#reporte.q_pripadnost = #reportparam[:q_pripadnost]
#reporte.datumpredaje = #date
if #reporte.save
redirect_to(:action => 'show', :id => #reporte.id)
else
redirect_to(:action => 'exportnew')
end
end
I think your problem in this case is that you use redirect_to instead of render. When you use redirect_to then you lose all the variables from your current action. I would probably do something like this in your encreate action:
if #reporte.save
render :show
else
render :exportnew
end
When you use render then it will use the variables from the current action but the view from the action you send to the render method. So when form_for is called with the #report variable, it is already populated with the values that was sent to encreate. Just make sure that you use the same variable names in the different actions but it looks like you do that already.

Rails problem display attribute key along with attributes value

I have the following problem. I have a form which takes input for a "Chart" object. But after processing the form, i wish to display one of the values, and it adds the key of this value.
Class model
class Chart
attr_accessor :title, :series
def initialize(title = nil, series = [])
#title, #series = title, series
end
end
View of form:
<% form_for :chart , :url => { :action => "show" } do |f| %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>...
<% end %>
Chart controller, show method:
def show
#chart = Chart.new(params[:chart])
end
View of show:
<h2><%=h #chart.title %></h2>
Which displays: "title"input_forms_title""
for example: writing in the input form: Economy, prints in the show view: "titleEconomy"
Any ideas?
I have just figured it out. The problem was in the constructor or initialize method. By changing the initialize method to:
def initialize( options = {} )
#title = options[:title]
#series = []
end
It now accepts all params perfectly!

Resources