Rails 4 action routes with simple_form and shallow nested resources - ruby-on-rails

resources :users, shallow: true do
resources :shoes
end
This gives me two different routes for create and edit
user_shoes_path
shoes_path
In my shoes _form.html.erb if I leave the form tag :url as default I get a missing routes error when I submit a new or updated shoe.
If I supply the url in the form I can get it to work for either the new or the edit update, but I can't get it to work for both.
This works for the new:
<%= simple_form_for :shoe, url: user_shoes_path do |f| %>
This works for the edit, but will fail once it tries the actual update since it redirects to /:param_id:
<%= simple_form_for :shoe, url: shoes_path(#shoe) do |f| %>
How can I make it work for both? Thanks.

You should use
<% = simple_form_for [#user, #shoe] do |f| %>
and let do simple_form do the work...
This case, if there is a #user, simple form will use it (as for a new), if there isn't (like for an edit), simple form won't use it...

Related

No route matches error

I'm building a Rails app and am making a form with form_for. I keep getting the error that there are no route matches for what I've specified, but when I run rake routes, I see the route I'm specifying (or at least I think I do). Can anyone help out?
My form_for tag is:
<%=form_for #party, :url => { :action => "update", :controller=>"parties", :method=>"patch" } do |f| %>
And in my parties controller I have:
def update
#party.find(params[:id])
#party.update_attributes
if #party.save
redirect_to '/login'
end
end
Also, my routes for the party model are seen below:
If you leave out the options, rails will figure out if it is a create/update form. Otherwise you will need to have separate forms for create/update if you specify options.
<%= form_for #parties do |f| %>
...
<% end %>

undefined method `posts_path' for #<#<Class:0x007fe3547d97d8>:0x007fe3546d58f0>

I'm new to rails and I'm getting this error:
undefined method `posts_path' for #<#<Class:0x007fe3547d97d8>:0x007fe3546d58f0>
I've posted my files below, please keep in mind I'm new to rails so simple explanations would be really appreciated!
Route.rb:
Rails.application.routes.draw do
get '/post' => 'post#index'
get '/post/new' => 'post#new'
post 'post' => 'post#create'
end
post_controller.rb:
class PostController < ApplicationController
def index
#post = Post.all
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to '/post'
else
render 'new'
end
end
private
def post_params
params.require(:post).permit(:content).permit(:title)
end
end
new.html.erb:
<%= form_for(#post) do |f| %>
<div class="field">
<%= f.label :post %><br>
<%= f.text_area :title %>
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit "Create" %>
</div>
<% end %>
I'm guessing form_for(#post) expects there to be a method called posts_path and one doesn't exist because it hasn't been defined in your routes file. Try replacing:
Rails.application.routes.draw do
get '/post' => 'post#index'
get '/post/new' => 'post#new'
post 'post' => 'post#create'
end
with
Rails.application.routes.draw do
resources :posts, only: [:new, :create, :index]
end
Edit: more info:
Read the full page on form helpers at http://guides.rubyonrails.org/form_helpers.html, and inparticular, read the section on "2.2 Binding a Form to an Object" and the part that says:
When dealing with RESTful resources, calls to form_for can get
significantly easier if you rely on record identification. In short,
you can just pass the model instance and have Rails figure out model
name and the rest:
## Creating a new article
# long-style:
form_for(#article, url: articles_path)
# same thing, short-style (record identification gets used):
form_for(#article)
## Editing an existing article
# long-style:
form_for(#article, url: article_path(#article), html: {method: "patch"})
# short-style:
form_for(#article)
Notice how the short-style form_for invocation is conveniently the
same, regardless of the record being new or existing. Record
identification is smart enough to figure out if the record is new by
asking record.new_record?. It also selects the correct path to submit
to and the name based on the class of the object.
So, knowingly or not, when you say form_for(#post), you're asking rails to guess the route that your form should be submitted to, based on the name of your #post variable. The routes that you had defined didn't match what rails expected them to be.
For more on routing in rails read the entire page at http://guides.rubyonrails.org/routing.html, and inparticular pay attention to the section "2 Resource Routing: the Rails Default". Your form_for(#post) will assume that you're using "resource routing", which is what I switched to.
As for why your getting a new error? There's somewhere else in your app where you were expecting to use your previous custom defined routes, and now you're using rails "resource routes" so your path names will be different. No route matches [GET] "/post/new" because now the route instead matches No route matches [GET] "/posts/new" (note the plural posts).
Here the form is try to find a route to a post_method through a path "posts_path"
So you need to define in your routes.rb file.
Rails.application.routes.draw do
get '/post' => 'post#index'
get '/post/new' => 'post#new'
post '/posts' => 'post#create'
end
The problem arises from the views. Rails cannot recognize the path that will run when the form is submitted.
You can manually change your form_for tag to point to the appropriate url.
<%= form_for #post, :url => "enter_your_path_here" do |f| %>
This solved my similar problem
you need to rename the post controller and the corresponding files to plural. that's posts not post. and then the route too needs to be resources :posts.
don't forget to change the class name of your post controller to be plural.

Using form_for with Nested Resources

I am building a To Do application in an attempt to get fluent with Rails. There are four levels of hierarchy in my app.
User
Goals (multiple goals per user)
Tasks (multiple tasks per goal)
Subtasks (multiple subtasks per task)
I have a working front end form for each of these that utilizes nested resources. My routes.rb has something like this
resources :goal do
resources :task do
resources :subtask
end
end
What I would like to do now is that have all these forms right in one of the views of the user controller.
This the form that I have attempted to create :
<%= form_for #task, url: {controller: 'task', action: 'create'} do |f| %>
<%= f.label :description %>
<%= f.text_field :description %>
<%= f.submit "Add Goal", class: "btn" %>
<% end %>
But I end up getting this error
No route matches {:action=>"create", :controller=>"task", :id=>"1"}
The :id=>1 corresponds to the user page I am on (http://localhost:3000/user/1)
What I understand is that there is that nowhere have I provided the goal_id for which this step is intended. No idea how to implement this.
Another thing that I have noticed is that a response to rake routes shows a lot of URI paths but nothing for POST method. It does not allow me to use a path from there in the url: in form_for because it does not match the POST method.
So my questions are :
How to route a form_for that when you have nested resources?
How to provide the ID of the parent resource while using form_for so that my create action is correctly routed?
It is typically bad practice to nest routes beyond two levels deep. I would change your routes to:
resources :goal do
resources :task
end
and
resources :task do
resources :subtask
end
Now if you run "bundle exec rake routes" in the command line you will see all of the nested routes and their corresponding helpers. Your current issue lies with the form_for method. You need to add the resource its nested with which in this case should be:
<%= form_for [#goal,#task] do |f| %>
blah blah
<% end %>
Lastly, #goal is also still undefined so you'll need to define it in your 'new' action in the tasks controller. This is normally done by passing the id of the goal your task will be associated with via the params hash and the "link_to" used to get to the 'new' form. Then in the new action in your tasks controller:
#goal = Goal.find(params[:goal_id]) #The parameter can be named anything
#task = Task.new
Then in your 'create' action you should have the association made:
#task = Goal.tasks.new(task_params)
if #task.save
flash[:success] = "Woot"
redirect_to somewhere_awesome_path
else
whatever
end

Re-writing Rails form helper in simple form

Is the following line in Rails Simple form
<% form_for #user :url => {:action => "attempt_login"}, do |f| %>
The same as the following in Rails form helper?
<%= form_tag(:action => 'attempt_login') do %>
If not, can you tell me what it would be? I need to redo some form code and I would like write down the correct syntax before running the app...
For in the case of passing parameters (i.e. :action) the simple form documentation is rather ambiguous.
Thanks!
The form_for is usually used for a specific record in order to update or create it.
Example:
# view in HAML (not ERB)
= form_for #user do |f|
= f.text_field :username
# matched with the routes
resources :users
other example with nested resources:
# routes.rb
resources :users do
resources :posts
end
# view in HAML
= form_for [#user, #post] do |f|
= f.text_field :content
Since you gave a record as an argument to the form_for method, it can "pre-fill" some fields of your record, i.e. if the #user already has a value for username, the field will be populated with that username.
It is true that you can specify an action to the form_for, something like this:
= form_for #user, url: { action: :custom_action } do |f|
The form_tag is used for the "other forms", such as a login form or a specific controller's action to be done.
Example:
# view in HAML
- form_tag action: :login do
= text_field_tag :username
= password_field_tag :password
To conclude, I would (based on my opinion) use the form_for helper if you are actually using a model's instance in the form and trying to modify/create it. So in your case, I would not use the form_for helper but use the form_tag instead (because you want a login form).
I recently migrated my form_tag methods to form_for because form_for was used in a gem that formatted my form using bootstrap. This was for a login form with no model. Here's how I used form_for without a model:
<%= form_for(:login, :action => 'attempt_login') do %>
I assume this works for simple_form as well:
<%= simple_form_for(:login, :action => 'attempt_login') do %>
Instead of using a form_tag, because the gem didn't decorate it, I used a form_for with a :symbol instead of a #model

How to post to a nested resource in Rails?

I have a nested resource in my routes.rb file:
resources :users do
resources :children
end
I have a form at /users/:id/children/new. Form comes up fine and the embedded ruby for the form looks like this:
<%= form_for(#user) do |f| %>
Problem is I want this to submit to /users/:id/children, but it submits to /users. Is there a standard way this should be done in Rails?
The embedded form shold look like this
<%= form_for [#user, Children.new] do |f|%>
<%= f.label :children_attr,.....%>
.
.
see this vedio, it might help.

Resources