Controller path for nested resource - undefined method `<controller>_path' - ruby-on-rails-3

I'm having trouble displaying my form at /users/2/friends/new. I'm receiving
undefined method `friends_path' for #<#<Class:0x21f0c14>:0x21ef364>
Here is the beginning of the form
<% form_for(#friend) do |f| %>
And the friends controller
def new
#user = User.find(params[:user_id])
#friend = #user.friends.build
end
This is the route
resources :users do
resources :friends
end
And the relevant path from "rake routes"
users/:user_id/friends/new(.:format) {:controller=>"friends", :action=>"new"}
Any help or insight is greatly appreciated. This is my first rails 3 app.

Try:
user_friends_path(#user)
It's because it's a nested resource:
http://guides.rubyonrails.org/routing.html#creating-paths-and-urls-from-objects
Update:
As for the form, you can do:
<%= form_for [#user, #friend] do |f| %>

Related

Rails 310 Redirect Loop

I'm going back to write a basic app with projects that have tasks. In my show view of a project I want to list the tasks and also include a form. When I wire this all up I get 310 Redirect loop. It's been a while since I've written anything from scratch so would appreciate some help looking at my code.
controller code:
def show
#project = Project.find(params[:id])
#task = #project.tasks.new(params[:task])
if #task.save
redirect_to #project, :notice => "Task added"
else
render action: :show
end
end
view code:
<%= #project.project_name %>
<%= form_for(#task) do |m| %>
<%= m.label :Task %>
<%= m.text_field :task_name %>
<%= m.button :submit %>
<% end %>
<% #project.tasks.each do |t| %>
<%= t.task_name %>
<% end %>
project.rb
has_many :tasks
task.rb
belongs_to :project
You are redirecting to #project, which is interpreted as meaning, redirect to the show page for #product. But you are calling redirect from the show page, hence the redirect loop:
request routed to show page
find project
task instantiated
task saved
redirect to show (loop back to 2)
Normally you don't create records in show, you do it in create. Any reason you're doing it this way?

Rails 3.2 One to Many View

I have tried to get this working, looked at multiple tutorials, questions on here tried different things for about a week now and I can't get the view to work correctly.
I have teams of users. A team has_many users and a user belongs_to a team (one team at a time). I know the association works because I got it working using the console (with some help there). I'm not sure how to get it working in the view. Below is the code, please let me know if more is needed.
What am I missing?
_join_team_button
<%= form_for(#user) do |f| %>
<%= f.submit "Join Team", class: "btn btn-large btn-primary" %>
<% end %>
Team Show Page
<%= render 'shared/join_team_button %>
Teams Controller
def show
#team = Team.find(params[:id])
#team_members = #team.users
#user = current_user.users.build if signed_in?
end
Users Controller
def show
#user = User.find(params[:id])
#teams = #user.team
end
I tried to put a complete demonstration of what you are looking for. Let me know if it fits for you.
#FILE: models/team.rb
class Team < AR::Base
has_many :users
end
#FILE: models/user.rb
class User < AR::Base
belongs_to :team
end
#FILE: config/routes.rb
#Here you are defining "users" as a nested resource of "teams"
resources :teams do
resources :users do
member do
put :join
end
end
end
#if you run "rake routes" it will show you the following line along with others
join_team_user PUT /teams/:team_id/users/:id/join(.:format) users#join
#FILE: controllers/team_controller.rb
def show
#team = Team.find(params[:id])
#team_members = #team.users
#user = current_user.users.build if signed_in?
end
#FILE: views/teams/show.html.erb
<% if(#user) %>
<%= form_for #user, :url => join_team_user_path(#team, #user) do |f| %>
<%= f.submit "Join Team", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>
#You dont really need a form for this. You can simply use `link_to` like below
<%= link_to 'Join', join_team_user_path(#team, #user), method: :put %>
#FILE: controllers/users_controller.rb
def join
# params[:id] => is the user_id
#user = User.find(params[:id])
# params[:team_id] => is the team_id
#team = Team.find(params[:team_id])
# Now make the relationship between user and team here.
#user.update_attribute(:team, #team)
end
Update:Based on your comment
Q: Do I create a new user's resource and nest that or do I nest the already establishes user's resource?
Ans: Based on your requirements any resource can be defined both independently or nestedly. But yes you can control that which method will be available in which way. Like in your case, you can allow only join method when your user is nested under team resource.
resources :users, :only=>:join do
member do
put :join
end
end
resource :users
run rake routes with and without :only=>:join option and see differences in available routes.
Q: Will that affect other things?
Ans: If you strictly define your routes following above example, it should not affect other things. You should confirm all the available routes to your application by rake routes.
Q: Should I put my current routes.rb file up there?
Ans: Assuming your current routes.rb will be modified in the above way. Could I answer the question?
Q: Confused about the comments controller?
Ans: Im extreamely sorry. Yes it must be users_controller.rb as the rake routes command is showing. Result of copy and paste from my own example code :P
Q: what should I put there? the build method
Ans: In your case both the user and team is already exists in your database. All you need to do is just setup a relationship. So you can just use update_attribute option. Ive changed the join method. Please check. But yes if want to create new entries you might need build methods.
Sorry for the late reply :)
I figured it out. Still not perfect, but it gets the association working. The team, and the user were already created, I just needed to establish the association, so the build method would not have worked. Here's what I have:
View:
<%= form_for(#user) do |f| %>
<%= f.hidden_field :team_id, :value => #team.id %>
<%= f.submit "Join Team", class: "btn btn-large btn-primary" %>
<% end %>
Teams Controller:
def show
#team = Team.find(params[:id])
#team_members = #team.users
#user = User.find(params[:id]) if signed_in?
end

Issues getting a profile to update and show newly submitted form item

Following up on a previous question, I have a few issues to resolve before I have a comment form showing and submitting securely on my profile. I'm a beginner to programming so thinking across multiple controllers seems to have me lost.
What I'm doing is posting comments in a form, then listing them.
Background: The _comment_form and _comment reside as partials in the Profile about. (My next task is toggling from about to other Profile information, but that's another question altogether.)
Using the help provided in my last question I feel like I'm almost there but am getting an error.
CreateComments migration:
t.integer :profile_id
t.integer :author_id
t.string :body
My Comment model:
class Comment < ActiveRecord::Base
belongs_to :profile
belongs_to :author, :class_name =>"User", :foreign_key => "author_id"
end
CommentsController:
def create
#comment = Comment.new(params[:comment].merge(:author_id => current_user.id))
#comment.save!
redirect_to profile_path(#comment.profile)
end
ProfilesController:
def create
#profile = Profile.new(params[:profile])
if #profile.save
redirect_to profile_path(#profile), :notice => 'User successfully added.'
else
render :action => 'new'
end
end
def show
#user = User.find(params[:id])
#profile = #user.profile
#comment = #profile.comments.new
end
Comment partials inside Profile partial:
<div id="commentEntry">
<%= render :partial => 'comment', :collection => #profile.comments %>
</div>
<div id="newitem">
<%= render :partial => 'comment_form' %>
</div>
Routes.rb:
resources :users do
resources :profiles
end
resources :comments
_comment_form.html.erb:
<%= form_for #comment do |f| %>
<%= f.text_field :body %>
<%= f.submit 'Add new' %>
<% end %>
_comment.html.erb:
<li class="comment" title="<%= #comment.author.profile.first_name %> <%= #comment.author.profile.last_name %>">
<%= #comment.body %>
</li>
So, Issue #1: Wrapping the _comment.html.erb in a loop <% for #comment in #user.profile.comments %> shows the profile but when I try and submit a new comment I get "Unknown action The action 'update' could not be found for CommentsController". If I take away the loop, the profile doesn't show and I get "NoMethodError in Profiles#show undefined method `profile' for nil:NilClass". Can anyone help me out and explain what I'm doing wrong?
Issue #2: I created a sample comment in rails console and when I get the profile to show, the input field for comment :body repopulates with the comment's body. Any ideas on what could be going on?
Short explanation of your problem:
The #comment you're getting in your _comment_form partial is one that's already saved in your database, hence the call to the update action and the body that's already filled.
You're creating the new comment just fine with #comment = #profile.comments.new in your show action, but it gets overridden somewhere else.
You're mentioning that you wrapped the _comment render in a loop with <% for #comment in #user.profile.comments %>, the problem is most likely there.
Fix:
The only thing you should have to change is the _comment partial to (without the for loop that you added):
<li class="comment" title="<%= comment.author.profile.first_name %> <%= comment.author.profile.last_name %>">
<%= comment.body %>
</li>
When you do the render :partial => 'comment', :collection => #profile.comments, rails is smart enough to loop over #profile.comments and give the comment (not #comment) variable to the partial.
How to avoid this the next time:
I'll give you two rules of thumb to avoid getting in this situation:
Try to name your variables more precisely. #new_comment would have been a better name for the variable to store the new comment. #comment is a bit ambigous as you've got a boatload of those in your view.
Avoid creating and modifying instance variables (# variables) in your views, try to do this only in your controller. I'll admit your particular case was a bit harder to detect because of the <% for #comment in #user.profile.comments %>. The view got its name for a good reason, it's only supposed to let you view the data you've defined in your controller.
Hope this helps.

Rails 3 nested resource route problem as form_for

I have nested resources like this in my routes.rb - (my rake:routes gist)
namespace(:admin) do
resources :restaurants do
resources :menus
resources :menu_items
end
end
In the controller:
def new
#restaurant = Restaurant.find(params[:restaurant_id])
#menu_item = #restaurant.menu_items.build
end
Trying to create a new MenuItem (action #new), by the url: http://127.0.0.1:3001/admin/restaurants/1/menu_items/new I get the error:
NoMethodError in Admin/menu_items#new
Showing /home/fps/workspace3/peded/app/views/admin/menu_items/_form.html.erb where line #1 raised:
undefined method `admin_menu_items_path' for #<#<Class:0xb6582d78>:0xb6581f2c>
Extracted source (around line #1):
1: <%= form_for #menu_item do |f| %>
...
How do I make this form work? It was created out of a nifty:scaffold
UPDATE
I also tried this in the _form:
<%= form_for [:restaurant, #menu_item] do |f| %>
But ended with a similar error:
Showing /home/fps/workspace3/peded/app/views/admin/menu_items/_form.html.erb where line #1 raised:
undefined method `restaurant_admin_menu_items_path' for #<#<Class:0xb68162b0>:0xb6813dd0>
Extracted source (around line #1):
1: <%= form_for [:restaurant, #menu_item] do |f| %
Should I file a bug?
form_for([#restaurant, #menu_item])
I think the problem is in the form. This worked for me:
<%= form_for(#menu_items, :url => restaurant_menu_items_path(#menu_items.restaurant)) do |f| %>
I'm having the same issue. The only solution I have found is to pass a url to the form_for.
<% url = (action_name == "new" ? {:action=>"create", :controller=>"admin/menu_item"} : {:action=>"update", :controller=>"admin/menu_item"})%>
<%= form_for [#restaurant ,#menu_item], :url=>url do |f| %>
One additional note, you will not get params[:menu_item] back, instead you will see params[:admin_menu_item].
Hope that helps you out!
You can look up your routes by running on the command line.
rake routes
It looks like you're calling your routes incorrectly.
Array notation would be:
form_for([:admin, #restaurant, #menu_item])
And the named route for create:
admin_restaurant_menu_items_path(#restaurant)
Dealing with nested resources and namespaces is a Vietnam (pita).
Here is my nasty solution:
= form_for #admin_menu_item,
:url => (#admin_menu_item.try(:new_record?) ?
admin_restaurant_menu_items_path(#admin_restaurant) :
admin_menu_item_path(# admin_menu_item)) do |f|
...
I hope you can help.
The only solution that worked for me correctly (for both new and edit resource) was:
form_for #menu_item, :url => url_for([:admin, #restaurant, #menu_item])
I'm using Rails 5 (not that I imagine it matters) and this worked for me:
= simple_form_for [:admin, #restaurant, #menu_item] do |f|
The fact that it's simple_form_for rather than form_for probably doesn't matter either.
Funnily enough, I'm building an app with the same exact resource names.

Rails 3 path for edit and new actions in a basic form view

I have the following routes:
resources :categories do
resources :articles
end
And the following views:
# edit.erb and new.erb files:
<%= render :partial => 'form' %>
# top of _form.html.erb file:
<%= form_for category_article_path(#article.category, #article) do |f| %>
But I have some troubles with the given path. I work with Rails 3. Here is an example of error that I get when testing:
undefined method `category' for
nil:NilClass
What is the basic way to write a such path? Many thanks.
Just pass a freshly newed up article (with an existing category) instance to the view.