I am useing a form_for helper to collect data on the client side of my application. However something weird is happening. I am not collecting the :name and :description and they are both returning as nil. this is my code:
<%= form_for #type do |f| %>
....
<%= f.text_field :name, :class => "col-xs-4" %>
<%= f.text_field :description, :class => "col-xs-4" %>
<%= f.submit %>
....
Do I need to make a fields_for under the form_for to get this working? It is a bit tricky because I am using #type which in this case is set up to tell the view which kind of attr. they are looking at. For example, this line:
<%= f.label #type %> <label> Description</label>
depending on what view you are on shows ether:
Group Description
or
Tag Description
and because they are both technically the same, I am using the same index for both. I hope I am clear with my issue and thank anyone who understands my problem and solution.
The param name will depend on the object you pass.
If #type contains an instance of Group, then you will get the params under params[:group], and if it is an instance of Tag, the you will get them on params[:tag]
<%= form_for #type do |f| %>
<%= f.label :name, "#{#type.model_name} Description" %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
Note the label definition. The way you are defining it will create 2 labels and the second one will not be linked to any field.
fields_for is normally used when you are creating several objects within the same form, for instance a Project and several tasks associated to it.
Hope this helps.
update:
If #type is a string or symbol it should work too. The tradeoffs using this approach will be that if there are any validation errors when creating the object, those will not be displayed and the fields will not be prefilled with the input that the user gave before submitting the form, forcing the user to enter all the information again and guessing which was the validation error (you can initialize it from the received params, but that complicates the code readability)
The unique thing different in your view would be the label definition.
<%= f.label :name, "#{#type} Description" %>
Related
I'm making an app where some activities are listed in a table called Fakultety (polish language, sorry), and participants on in another table called Uczestnicy.
I have a submit form where you can submit yourself to an activity, but I'm stuck on passing values to a DB. Firstly, I don't know how to tell to the database on which activity you want to be assigned to (I tried to change the submit button id to an activity id and then passing it into a database but don't know how to do this id: "#{#fakultet.id}" not working) and later I want to count how many people are assigned to field participants in a database Fakultety, but I don't want to pass all the data, just ID of the users from table called Uczestnicy. How to do it? I mean just to pass the ids to another table, and how to tell the database on which activity I want to be assigned to?
This is my form view:
<h1>Zapisujesz sie na fakultet</h1>
<div class="form-group">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#participant, url: zapisy_path) do |f| %>
<p>Imię:</p>
<%= f.text_field :firstName, class: 'form-control' %>
<p>Nazwisko:</p>
<%= f.text_field :lastName, class: 'form-control' %>
<p>Grupa:</p>
<%= f.text_field :group, class: 'form-control' %>
<%= f.submit "Zapisz się", class: "btn btn-primary" id: "#{#fakultet.id}"%>
<% end %>
</div>
</div>
</div>
Does anybody understand me and can help me?
Rails provides form collection helpers that make it really easy to assign associations:
# I'm going to just do this in english
<%= form_for(#activity) do |f| %>
<%= f.collection_select(:participant_ids, Partipicant.all, :id, :name, prompt: true, multiple: :new) %>
# ...
<% end %>
Then whitelist the attribute as an array:
params.require(:activity).permit(:foo, :bar, participants_ids: [])
Thats all you actually need to assign childen to to a parent resource. This is done as a part of the normal create/update actions of the parent resource.
You don't actually need the form for the child records unless you actually want to be creating the record. In that case you can setup a nested resource or if you want to create/edit multiple nested records at the same time as the parent record you can use nested attributes.
First you should rename your models and tables, to English, it's a really bad pattern to use your language, in English it is easier to understand by other devs.
According to the problem, probably what you are looking for is hidden_field
<%= f.hidden_field :fakultet_id, :value => #fakultet.id %>
and if you want to query Fakultety that have user assigned, you can select Fakultety where participant_id is not nil
Fakultety.where.not(participant_id: nil)
I'm building a page that contains a html table, where the user can choose the name in the table header and the content in the table row.
The user will enter the information to a form, which will be parsed into a hash and saved into the DB.
Here is an example where :key will be a key of the hash (table header text) and :value will be a value in the hash (table column content).
<%= form_for([#page]) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.text_field :key1 %>
<%= f.text_field :value1 %>
<%= f.text_field :key2 %>
<%= f.text_field :value2 %>
<%= f.text_field :key3 %>
<%= f.text_field :value3 %>
<%= f.text_field :key4 %>
<%= f.text_field :value4 %>
<%= f.submit "Save" %>
<% end %>
I could make a new DB table with a has_many association to the page DB and have the info stored in that table. Then that data can be rebuilt into a hash when I need to render the view.
But if I could save the entire hash into a column in the page DB, then it would save me from having to rebuild the hash every time someone visits the page.
I'm struggling to come up with how to do this in form_for.
The first issue is that it requires key and value columns in the page table. A simple fix would be change all inputs into <%= f.text_field :html_table %> (for html_table column in the page table). But then it won't be able to distinguish between a key and a value in the hash. And I also don't have any way of telling it to put the info together into a hash that is then stored into the page table's html_table column.
Not sure if this is even a possible thing but it doesn't hurt to ask before I go ahead with building the has_many association table and setting it up that way.
I'm rather confused about your question.
Can't you build a hash like this in your controller action?
html_table = {
params[:key1] => params[:value1],
params[:key2] => params[:value2],
params[:key3] => params[:value3],
params[:key4] => params[:value4]
}
Then save it to #page.html_table attribute.
EDIT:
In this case, the form is not about attirbutes of a particular object. So instead of using form_for (Link), you should be using form_tag (Link).
Example:
<%= form_tag "/pages_controller/build_html_table" do %>
<%= text_field_tag "key1" %>
<%= text_field_tag "value1" %>
<%= submit_tag "Save" %>
<% end %>
I am using the cocoon gem to try and achieve adding an object which belongs to another with nested fields. I have a 'user_resolution' which has many 'milestones'. I have set up the associations accordingly in both of these models. For some reason, milestones are failing to be created, however if I add one manually in the database I can successfully update it. I am able to dynamically add the fields and remove them using the cocoon gem but that is all. When I click 'add milestone' it redirects me to the show view of the user resolution and throws the success message saying user resolution has been updated, no errors are thrown but the milestone(s) is/are not created.
user_resolution.rb
has_many :milestones
accepts_nested_attributes_for :milestones, reject_if: :all_blank, allow_destroy: true
milestone.rb
belongs_to :user_resolution
I have set up the nested form within the edit view as for now I only want users to add a milestone to a resolution in the edit view.
user_resolutions/edit.html.erb
<%= form_for(#user_resolution) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br>
<%= f.text_area :description %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<%= f.fields_for :milestones do |milestone| %>
<%= render 'milestone_fields', f: milestone %>
<% end %>
<%= link_to_add_association 'Add Milestone', f, :milestones %>
<%= f.submit "Add Milestone" %>
<% end %>
_milestone_fields.html.erb
<div class="nested-fields">
<div class="field-row">
<%= f.label :name, 'Name' %>
<%= f.text_field :name %>
</div>
<div class="field-row">
<%= f.label :description, 'Name' %>
<%= f.text_area :description %>
</div>
<div class="field-row">
<%= f.label :severity, 'severity' %>
<%= f.check_box :severity %>
</div>
<div class="field-row">
<%= f.label :target_date, 'target_date' %>
<%= f.date_select :target_date %>
</div>
<%= link_to_remove_association 'Remove', f %>
</div>
The permitted parameters within the user resolutions controller also contain the following
milestones_attributes: [:id, :user_resolution_id, :name, :description, :target_date, :severity, :complete, :_destroy]
The milestones themselves have no views, they only have a model and a controller. The controller create action (which i'm unsure is required for nested forms) contains the standard following code
def create
#milestone = Milestone.new(milestone_params)
if #milestone.save
redirect_to user_resolutions_path,
:flash => { :success => "You successfully created a milestone" }
else
redirect_to new_milestone_path,
:flash => { :error => "Oops something went wrong. Try again." }
end
end
I've been as informative as I can but if you need anything else let me know. Thanks guys.
which i'm unsure is required for nested forms
You don't need a create action for milestones - they'll be populated from the user_resolutions#create controller action.
There are several things to look at with this. I'll detail some here. This won't be a specific answer, but may help point you in the right direction.
Firstly, you need to make sure you're receiving the correct params.
Cocoon does a great job building the nested form - you need to make sure it's obliging Rails' nested attribute structure.
To do this, you should right-click > view source.
In the f.fields_for section (it won't be called that in the HTML), you'll be looking for the equivalent to the following:
<input type="text" name="milestones_attributes[0][name]" value="">
The important thing to note is the name...
Each time you use a form, or any Rails view helper for that matter, you're really just building standard HTML. form_for just creates an HTML form, and thus any params contained within it need to adhere to a certain structure for Rails to recognize the params.
The f.fields_for elements will typically be called x_attributes[:id][:param] - this is passed to Rails, which cycles through each [:id] to determine the number of nested params to add.
You need to check the source for the above naming structure. If you see it, that's good. If not, it means you haven't built your form properly.
Secondly, you need to make sure your objects are being built in the controller.
I'm not sure how Cocoon does this, but essentially, each time you use f.fields_for, you have to build the associated object before:
def new
#user_reservation = UserReservation.new
#user_reservation.milestones.build #-> this is what makes f.fields_for work
end
If the first step shows incorrect element naming, it means your associative objects are not being built (which is why they're not being recognized).
To test it, you should build the associative objects in the new method, before sending.
Finally, you'll want to post your params.
These tell you in explicit detail what Rails is doing with the nested attributes, allowing you to determine what's happening with them.
Sorry for the long-winded answer. You'll not have received any answers anyway, so I felt it prudent to give you something.
I have a controller named Welcome with view called index.
In my index view i have created a small form as such.
<%= form_for :location do |f| %>
<%= f.label :Longitude %><br>
<%= f.text_field :integer %>
<br>
<br>
<%= f.label :Latitude %><br>
<%= f.text_field :integer %>
<p>
<%= f.submit %>
</p>
<% end %>
In this form the user can enter some integer value for longitude and latitude. Once the user enters value for longitude and latitude. They click submit. Upon submit i would like to store these values in my controller. So i am using the following method where i have two instance variables taking values from the form.
def index
#long = params[:longitude]
#lat = params[:latitude]
end
In my routes.rb I have
get 'welcome/index'
post 'welcome/index'
Please tell me where i went wrong. Also if someone can suggest a better way of doing this also i would appreciate it i am new to rails and i want to learn the correct way of doing things so i don't create bad habits early on.
The reason it's not working is because your fields are both named :integer, and since they share the same name, the browser will only send one value.
So, with your code, if you filled in the first field with 'a' and the second with 'b', your params would contain something like this:
{ location: { integer: "aaa" } }
Which obviously isn't what you want! If your HTML looked more like this (I've stripped the layout stuff to make things clearer):
<%= form_for :location do |f| %>
<%= f.label :longitude %>
<%= f.text_field :longitude %>
<%= f.label :latitude %>
<%= f.text_field :latitude %>
<%= f.submit %>
<% end %>
Then you could access the params in your controller params[:location][:longitude] and params[:location][:latitude]
A good idea to see the difference between the effect of your form vs this form would be to inspect the html. Take a look at the input name attributes, and label for attributes and see how they match up with the params Rails receives. Also, when you post the form, be sure to look in your server log to see the params! :)
After reading your question, I think you want to see how controllers, views and models work. For learning purpose you can generate scaffold and study the generated code.
For example, generate a model GeoLocation, related controller and views by this:
rails g scaffold GeoLocation longitude:string latitude:string
Now fire up rails server and browse http://localhost:3000/geo_locations/new and save your long, lat. I wrote this answer to give you some guidance.
You can follow these excellent books:
The book of Ruby
The Rails 4 Way
I'm developing a simple rails app where I want to plot some stock charts. The problem is that when I start my server and load localhost the default value/ticker symbol is not loading which means that I have to type in a ticker in my form for it to work.
I found this thread where I learnt how to write a default value in my form/view, like so:
<%= form_for :find_it do |f| %>
Ticker symbol: <%= f.text_field :string, :value => "JPM" %></br>
<%= f.submit "Find" %>
<% end %>
and that's all fine, but it does not submit the value by default.
So how do I go about fixing this and what is the best practice?
In your input field you have list your attribute as a string, while that is the type, it most likely isn't the actual name of the attribute you wish to save "JPM". So you should change
<%= f.text_field :string, :value => "JPM" %>
to
<%= f.text_field :attribute_name, :value => "JPM" %>
If I copy and paste your form into a Rails app on my machine it does display a text field populated with "JPM", which I believe is correct.
When you hit submit the form will post to a create action with params containing:
"find_it"=>{
"string"=>"JPM"
}
Another thing I noticed is that you have f.text_field :string. This should be the name of your attribute, rather than the type (i'm assuming that you don't have a field called string).