Pass variables without model associations in Rails - ruby-on-rails

I have a variable that I want to pass with a form in rails.
The variable is not convenient because it is not part of the model. I really don't want to create a column in the DB just so I can pass the variable.
When I try to pass the variable using something innocuous like:
<input type="hidden" id="blah" value=<%= "#{#blah}" %> />
The hidden field turns up correctly in the source, but doesn't pass with the params hash. When I code it properly with something like id="review_blah" rails assumes it's part of the review model and gets angry because it isn't part of the model.
Isn't there some workaround?? Some way to pass a variable easily for these circumstances, without rebuilding your model?
Thanks

You need to define an attribute_accessor for the virtual attribute and you need to add it to the attr_accessible list so it can be used in form. Like this:
attr_accessor :blah
This makes the blah and blah= methods available which you can use to deal with the incoming data.
def blah=(data)
#do sth. with the submited data here
end
In this case you could access the data entered in the "blah" field as the local variable "data".
Then you need to make it a part of the regular form:
<%= f.hidden_field :blah, :value => <Your value here> %>
So the last thing you need to do is adding the field to the attr_accessible list.
attr_accessible :blah,....
Otherwise the request would fail because of mass assignment protection.

In model
attr_accessible :blah

Though it's very ugly you can do something like following
<input name='x' type="hidden" id="blah" value=<%= "#{#blah}" %> />
in your controller
#model.save
Model.update_all({:my_attribute => params['x']}, {:id => #model.id})

You need to set the name of the input parameter I think. otherwise it will not be contained in Rails params hash.
<input type="hidden" id="blah" value=<%= "#{#blah}" %> name="blah"/>

class ModelName
attr_accessor :blah
end
#model = ModelName.new
#model.blah = "blah blah"
#model.blah #will return "blah blah"
You don't need to have a column in your table. Check here
This way you can have
=form_for #model do |f|
=f.hidden_field :blah
This will pass blah along the object in the params hash.

Related

How to render the correct field name for a 'fake' simple_form_for field

I used a fake input field to get simple_form to render a field that doesn't correspond to a field in the model.
class FakeInput < SimpleForm::Inputs::StringInput
def input(wrapper_options = nil)
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
template.text_field_tag(attribute_name, nil, merged_input_options)
end
end
In my form, the model I am working with is deeply nested. This means the input name is long and very specific. An Event has_many Positions which has_many Responsibilities. I want to add a fake field to the responsibilities called position_count.
As you can see in the markup below, the label gets the correct value for its for attribute but the input does not get the correct name attribute. What do I need to change (possibly in the fake_input.rb class?) to get the input to have the correct name?
The correct name for the input should be
event_positions_attributes_0_responsibilities_attributes_0_position_count
but the fake field is only rendered as
position_count
The markup being rendered is...
<div class="input fake optional event_positions_responsibilities_position_count">
<label for="event_positions_attributes_0_responsibilities_attributes_0_position_count" class="fake optional control-label">Position count</label>
<input type="text" name="position_count" id="position_count" class="fake optional">
</div>
Its because you are using text_field_tag - this is one of the "low-level" form helpers that is not bound to an object.
So when you call template.text_field_tag(attribute_name, nil, merged_input_options) it actually uses attribute_name for the name attribute.
This differs from SimpleForm::Inputs::StringInput that uses #builder.text_field(attribute_name, merged_input_options) which is bound to an object.
An easier way
A far simpler way to create an input that does not correspond to a database column is by using "virtual attributes" - in other words just a plain old instance variable with a getter and setter.
class Responsibility < ActiveRecord::Base
# ...
attr_accessor :position_count
end
<%= simple_form_for(#responsibity) do |f| %>
<%= f.input :position_count %>
<% end %>
By default, Simple Form will look at the column type in the database
and use an appropriate input for the column.
Thats not possible in the case - I do believe it will fall back to :string (<input type="text>") - you can use the as option if you want a specific type of input.

Ruby On Rails : I need some explanations about form

I am creating a RoR application. So i want to create a web form with select drop down type. I found the following code in a project. Here is a form:
<div class="field">
<%= f.label :key_words %><br>
<%= f.collection_select(:skill_list, User::all_tags, :name, :name, {},{multiple: true}) %>
</div>
I create in User controller class :
class UsersController < ApplicationController
...
def all_tags
#tags = Tag.all
end
end
Here is database :
1. I don't understand what is User::all_tags ? Ok understood
2. I cannot see tags in my select drop down. What is missing ?
You need to understand the context first, and then need to understand it.
You are passing: User::all_tags, :name, :name
User::all_tags returns you most probably an array/hash, and this array will be utilized to populate collection_select, but a general option tag has two things: 1) value that will exactly be sent to the server, and a piece of text that will be shown, but won't necessarily be sent to the server.
The first argument after User::all_tags determines what to have for value, and second argument decides what to have for that apparent text.
<option value="First argument goes here ">"Second argument">/option> # this isn't valid code
It seems to me all_tags a method that placed in user class and have an array or hash containing the values
you can call that method like User.all_tags as well

Unexpected naming of fields using Reform Form Object with Composition

ANSWER: The model calls were redundant. There should only be one and the last one in this example was the winner. I was misusing the Form Object DSL. :/
I've got a Reform Form object in a Rails 4.1 form that is structured like...
Form Object
class MyForm < Reform::Form
include Composition
model :user
model :user_group
property :name, on: :user_group
property :email, on: :user
end
Controller
# ...
#form = MyForm.new(user: User.new, user_group: UserGroup.new)
# ...
View
<%= form_for(#form) do |f| %>
<%= f.text_field(:name) %>
<%= f.email_field(:email) %>
<% end %>
Rendered HTML
<input type="text" name="user_group[name]" id="user_group_name">
<input type="email" name="user_group[email]" id="user_group_email">
My question is why are the fields seeming to ignore the model mappings and rendering them to the wrong model name? What am I doing incorrectly here?
You can call ::model only once! Once you call it with the correct model (or any name), the rendering will name the fields to whatever ::model you specify. The point about Reform is to hide internals about your model names!

Rails simple_fields_for can't hide :id

I've been using simple_form for rails together with HAML
I have a number of line_items they have a unique id which i retrieve from the Order object
= f.simple_fields_for :line_items do |line_items|
.f.input :id unless #order.status?
.f.input :cost unless #order.status?
However, whenever i iterate through these list, i would like to hide (remove from the form) the line_items id, i try to put a unless statement to remove other parameters and it works (eg. :cost) but for the :id it appears to be a hidden fields
<input id="order_line_items_attributes_2_id" name="order[line_items_attributes][2][id]" type="hidden" value="26">
How can i successfully remove IDs from appearing in the fields just like how i did it for :cost?
try this:
= f.simple_fields_for :line_items, include_id: false do |line_items|
more on this: http://apidock.com/rails/ActionView/Helpers/FormHelper/form_for
Rails thinks that you should NEVER need to edit the :id, so it makes it difficult or impossible. If you want to DISPLAY the :id, that's fine, but there would be limited reason to present the :id such that it can be edited.
I'd just always display the id in the form.
A work around...
I tricked the system, by rending the fields as i uses HTML comment to stop it from appearing and stopped it from being submitted
/ =f.input :id unless #order.status?
I uses = instead of - so as the fields would be able to be rendered however hiding inside the html comment
<!--<input class="hidden" id="order_line_items_attributes_2_product_id" name="order[line_items_attributes][2][product_id]" type="hidden" />-->

how to use an array in form_for?

I've got a user model which contains a field called, lets say, text1. In the users/new form I want to have 4 individual text boxes for this text1. In my model I will take values from these boxes and concatenate them together as comma separated values and store them in the DB. To give you an understanding, this is what I want.
<input type="text" name="user[text1][]" />
<input type="text" name="user[text1][]" />
<input type="text" name="user[text1][]" />
<input type="text" name="user[text1][]" />
How do I get this using form_for helper method? For now please don't worry yourself about the accessor method in the model, that is all taken care of. Thanks a ton.
Add few virtual attributes to your User model
class User < ActiveRecord::Base
attr_accessor :text1_part1
attr_accessor :text1_part2
attr_accessor :text1_part3
attr_accessor :text1_part4
def before_validation
self.text1 = "#{self.text1_part1}#{self.text1_part2}#{self.text1_part3}#{self.text1_part4}"
end
# make sure you fill the correct values for
# the text parts for an existing record.
# This can be done by implementing `after_find` or overriding
# `text1=`.
end
In your view code use the new attributes instead of text1
<% form_for(:user) do |f| %>
#some code
<%= f.text_field :text1_part1>
<%= f.text_field :text1_part2>
<%= f.text_field :text1_part3>
<%= f.text_field :text1_part4>
#some code
<%= f.submit "Save">
<% end %>
The previous answer gives a solution, so I am just providing some background as to why what you are asking for does not work they way you might hope.
You can indeed create a form with multiple input fields of the same name, and that data will be posted. However, when rails receives the post it automatically parameterizes the post data and/or url parameters. It essentially splits on the & and assigns the key/value pairs to the params hash. The outcome of this is that params[:user][:text1] (from your example) will have the value of the last instance of the user[text1] it encountered, since it is simply a value assignment to an existing key. You might want to dig into ActiveRecord multiparameter assignments to get an idea of how datetime attributes work, since they are similar to your use-case.
I am working on something similar and it sounds like maybe serialization is what you are looking for. Unfortunately I don't have my issues solved yet, so I can't provide anything more concrete.

Resources