I have a nested form
form_for #post do |f|
f.fields_for #ingredients do |ingredient|
ingredient.text_field :name
end
end
link_to "Add ingredient","#"
This is the basic structure. I want a new name field added when you click on "Add ingredients". As I have to pass ingredient(form builder) for making a new field, I am unable to use ajax. There is no way for me to make a new ingredients object using java script in rails.
I see, people working with link_to_function. But I see that is deprecated.
Can anyone suggest a solution for this?
Related
I have a model called sections, which has many feedbacks. This is working ok, and on the 'section' show page I can show the associated 'feedbacks' like so:
<% #section.feedbacks.each do |feedback| %>
<%= feedback.name %>
<%= link_to 'Show', feedback %>
<%= link_to 'Edit', edit_feedback_path(feedback) %> |
<% end %>
Works fine. But now I need a button that takes me to the create page for a new feedback item, and it needs to be associated to this 'section'.
At first I did it with a nested form, but the feedback items have quite a lot of fields and so it's messy to do it all on one page.
I'm new to ruby, so hopefully it's a really simple thing!
Thanks in advance for any help,
James
You should use nested form for it. If your form contains many fields then use bootstrap wizard for it.
or
<%= link_to 'New', new_feedback_path(section_id: #section.id) %>
& in your new method of feedback_controller , write the below:
#feedback = Feedback.new
#feedback.section_id = params[:section_id]
What you are trying to do is pretty much standard Rails stuff and you need to read a bit more of the official guides. You will need:
A controller with different actions for feedbacks (edit and new for example)
Some views for the above actions. The edit and new views can share the same form.
Routing to make it possible to work with a Feedback in the context of a Section.
Like:
resources :sections do
resources :feedbacks
end
This will allow you to use the following instead of your edit link:
<%= link_to 'Edit', edit_feedback_path([#section, feedback]) %>
And will go to this edit route:
/sections/:section_id/feedbacks/:feedback_id
You will also have the following new route available:
/sections/:section_id/feedbacks/new
Which will allow you to get the right section from the url params in order to create a feedback for it.
I know I've written it wrong, but I'm looking at the documentation and can't figure out how.
My model is Quote and has three fields, body, attribution, and work, all strings. The form is intended to add a new quote to a page of quotations.
on main/index.html.erb
<%= form_for(:quote, url: {action: 'create'}) do |f| %>
<%= f.text_field :body %>
<%= f.text_field :attribution %>
<%= f.text_field :work %>
<%= submit_tag "Submit" %>
<% end %>
in main_controller.rb
def create
Quote.create(body: params[:body], attribution: params[:attribution], work: params[:work])
end
The form submits, and an entry is saved to the database -- but it's a totally blank entry. I'm not sure why. Help would be appreciated!
Three things:
The way rails forms are supposed to work, you're not meant to get body, attribution, etc independently, they should be wrapped up into a quote object. But...
In your form, your not properly binding an object to the form the way rails expects. You can read more in the documentation here: http://guides.rubyonrails.org/form_helpers.html#binding-a-form-to-an-object. You could also generate a fake scaffold rails generate scaffold HighScore game:string score:integer to generate a fake model and see an example of how it's supposed to work. The default scaffolding even has simple examples of how to deal with save errors.
Finally, as #Paven suggested, when you get confused, be sure to look at what's going on in your log - i.e. what params are being posted to your create action. That is always helpful and a good way to diagnose problems quickly.
Your form does't need the action argument. The form_for helper uses ActiveRecord objects to determine the path, meaning as long as you build your object correctly, you won't need to determine your path individually:
<%= form_for #quote do |f| %>
Secondly, you'll want to look at your create method:
#app/controllers/quotes_controller.rb
def new
#quote = Quote.new
end
def create
#quote = Quote.new(quote_params)
end
private
def quote_params
params.require(:quote).permit(:body, :attribution, :work)
end
The problem is you're not sending an ActiveRecord object to your form_for helper. You can read the explanation here:
In Rails, this is usually achieved by creating the form using form_for
and a number of related helper methods. form_for generates an
appropriate form tag and yields a form builder object that knows the
model the form is about. Input fields are created by calling methods
defined on the form builder, which means they are able to generate the
appropriate names and default values corresponding to the model
attributes, as well as convenient IDs, etc. Conventions in the
generated field names allow controllers to receive form data nicely
structured in params with no effort on your side.
In order to get the form working correctly, you need to be able to provide a valid ActiveRecord object (#variable), which the helper can use to determine the url etc
My code above helps you provide a new ActiveRecord variable, and allows you to use it in the form. This should allow the form_for method to send your data to the create method, which will then create & save an object in the db for you
I am an newbie. I have read the API documentation. But still don't understand how form_for works.
Firstly, from Ruby on Rails Tutorial, the form for follow button:
<%= form_for(current_user.relationships.build(followed_id: #user.id)) do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>
I understand current_user.relationships.build(followed_id: #user.id) means a new record. But why can we not just submit and trigger controller to save the record without hidden_field? Why do we still need to post followed_id to controller?
Secondly, in hidden_field, what does :followed_id means? I believe that is a symbol, i.e. it equals only "followed_id" not a variable of id. If that is only the name of the input field, then what is its value?
Thirdly, how does form_for know where the submission should be sent to? Which controller and action the form_for will post to?
Fourth, how does params work with form_for? In this follow button case, params[:relationship][:followed_id] will return #user.id in controller. How does it know the first hash attribute is :relationship? We have neither mentioned form_for :relationship nor form_for #relationship.
I know these questions can be very dumb, but I am really stuck. Any help will be appreciated.
I didnt do that tutorial so mind me if i dont answer directly to your question.
Take a look at the rails guide about form helpers and it explains in details your questions, probably in a more articulate way than i can.
form_for(path/to/your/controller/action) is a helper method to create HTML form elements with the url path to the POST or GET request. The helper knows if it should be a new record or an update record based on what you are asking to do in your controller action.
For example
In your controller
def new
#my_instance_variable = Myobject.new
end
In your view new.html.erb
<%= form_for #my_instance_variable do |f| %>
...
<% end %>
In your case the logic was directly written in the helper and you could also directly write
<%= form_for Myobject.new %>
Both will result with the following html
<form action="/myobjects/new" method="post">
# in this case rails knows its a `POST` request because the route new action
# is by default a POST request. You can check these routes and their request
# by using `rake routes` in terminal.
Then the hidden_field is another helper to contain a value, in your case the #user.id that will be passed as parameter then saved as a Create or update action for the given object. The reason it doesnt add the value in the hidden field tag is because you already have a model association that knows the id of user since the link of form uses the build method with user id.
Last part you need to understand the form_for link logic
current_user.relationships
# implies the association of the current_user has many relationships
current_user.relationships.build
# .build is a method to populate a new object that can be save as a new record
# means you will create a new relationship record by populating the user_id
# column with the current_user.id and the followed_id with the target #user.id
After reading the book The Rails 4 Way, I understand form_for better now.
11.9.1.5 Displaying Existing Values.
If you were editing an existing instance of Person, that object’s attribute values would have been filled into
the form.
in this way, when we build the relationship by usingcurrent_user.relationships.build(followed_id: #user.id), the relationship instance will be created and gain attribute followed_id. So that, instead of "creating" a relationship, we are actually editing the relationship by the form.
Then Rails will know you are editing and load the existing attribute "followed_id" to the field. Therefore, we don't need to assign value to the field like using f.hidden_field :followed_id, value: #user.id.
And the reason why we have to use a field to pass followed_id to params is because HTTP server is stateless, it doesn't remember you are creating a relationship with which user.
One of the advantages of writing form_for current_user.relationships.build(followed_id: #user.id) instead of standard form_for #relationship is we don't need to write "if-condition" in controller like this:
unless current_user.nil?
if current_user.following?(#user)
#relationship=current_user.relationships.find_by(followed_id: #user.id)
else
#relationship=current_user.relationships.new
end
end
params will be sent to the controller which belongs to the instance's model. "post" method will go to action create, "delete" will go to destroy, "patch" will go to update, etc.
params will be a hash with another hash inside like { instace_name: { field_1: value1, field_2:value2 } } or full params as below
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"afl+6u3J/2meoHtve69q+tD9gPc3/QUsHCqPh85Z4WU=",
"person"=>{"first_name"=>"William", "last_name"=>"Smith"},
"commit"=>"Create"}
I have two nested forms:
<%= form_for(#post, remote: true, html: { class: "postform"}) do |f| %>
...
<%= form_for(Tag.new) do |ftag| %>
...
end
end
Now, i want to submit the innerform "ftag" to a create a new "Tag" using ajax,
give that back to my view to populate the view with new tags (Tags and post has a HABTM-relationship)
My question is, how to do this "the-rails-way"?
If i just can get the post and create a new tag to work, i can manage the callbacks et c myself i hope.
I was thinking of doing this, though i dont think that is the correct way of doing it:
Using jquery,
Add a listner to a button inside of the form, and posting to my controller outside of rails, and pushing the response back to my view.
Is there a better way of doing this?
Thank you
I am rendering a form using form_for with an existing model. I would like to submit that model and get the next action to be performed to be the 'create' action. The docs have this example:
<%= form_for #post do |f| %>
<%= f.submit %>
<% end %>
And say "In the example above, if #post is a new record, it will use “Create Post” as submit button label, otherwise, it uses “Update Post”."
I am relatively new to rails and am not sure what to make of the following stuff in the docs about customizing using I18n. How can I get the submit button to use "Create" when there's an existing record?
Clarification. . .
I the form_for is being rendered out of the new action, but I am passing it an existing object, so that fields can be prepolulated. I want it to then go to the create action, but it is going to the update instead.
Update. . .
I realize now that the issue is with the form_for and not the submit, but haven't yet figured out how to modify the form_for so that it sends to the create action.
http://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-submit
There are three options, you can either override it in the translations file (config/locales/en.yml).
en:
helpers:
submit:
create: "Create %{model}"
update: "Create %{model}"
Or you can specify a value on the submit method.
f.submit("Create Post")
Or, you can keep the translations file as it is by default and do:
f.submit(t('helpers.submit.create'))
form_for will update a existing record instead of create, so basically you have to feed it a new record. The best way to do this is in the controller with record.dup. Something like
#post = #existing_post.dup
dup will create a shallow copy, allowing you to save it as a new record.