Mamboo!
Am new to RoR and using Lynda Ruby on Rails 4 Essential Training.
I keep getting " Unknown Action, The action '1' could not be found for SubjectsController" After pressing "Update Subject", on my edit page. I think it can not find update function! What is missing here?
Route.rb
Rails.application.routes.draw do
resources :subjects do get 'index', on: :collection end
match ':controller(/:action(/id))', :via => [:get, :post]
end
subjects_controller.rb
class SubjectsController < ApplicationController
layout false
def index
#subjects = Subject.sorted
end
def show
#subject = Subject.find(params[:id])
end
def new
#subject = Subject.new({:name => "Default"})
end
def create
#subject = Subject.new(subject_params)
if #subject.save
flash[:notice] = "Subject Created Successfully"
redirect_to(:action => 'index')
else
render('new')
end
end
def edit
#subject = Subject.find(params[:id])
end
def update
#subject = Subject.find(params[:id])
if #subject.update_attributes(subject_params)
flash[:notice] = "Subject Updated Successfully"
redirect_to(:action => 'show')
else
render('edit')
end
end
def delete
#subject = Subject.find(params[:id])
end
def destroy
#subject = Subject.find(params[:id])
#subject.destroy
flash[:notice] = "Subject Destroyed Successfully"
redirect_to(:action => "index")
end
private
def subject_params
params.require(:subject).permit(:name, :position, :visible)
end
end
edit.html.erb
<%= link_to("<< Back to List", {:action => 'show'}, :class => 'back-link') %>
<div>
<h2>Update Subjects</h2>
<%= form_for(:subject, :url => {:action => "update", :id => #subject.id}) do |f| %>
<table summary="Subject form field">
<tr>
<th>Name</th>
<td><%= f.text_field(:name) %></td>
</tr>
<tr>
<th>Position</th>
<td><%= f.text_field(:position) %></td>
</tr>
<tr>
<th>Visbile</th>
<td><%= f.text_field(:visible) %></td>
</tr>
</table>
<div class="form-buttons">
<%= f.submit("Update Subject") %>
</div>
<% end %>
</div>
rake routes
$ rake routes
Prefix Verb URI Pattern Controller#Action
sections GET /sections(.:format) sections#index
POST /sections(.:format) sections#create
new_section GET /sections/new(.:format) sections#new
edit_section GET /sections/:id/edit(.:format) sections#edit
section GET /sections/:id(.:format) sections#show
PATCH /sections/:id(.:format) sections#update
PUT /sections/:id(.:format) sections#update
DELETE /sections/:id(.:format) sections#destroy
pages GET /pages(.:format) pages#index
POST /pages(.:format) pages#create
new_page GET /pages/new(.:format) pages#new
edit_page GET /pages/:id/edit(.:format) pages#edit
page GET /pages/:id(.:format) pages#show
PATCH /pages/:id(.:format) pages#update
PUT /pages/:id(.:format) pages#update
DELETE /pages/:id(.:format) pages#destroy
subjects GET /subjects(.:format) subjects#index
POST /subjects(.:format) subjects#create
new_subject GET /subjects/new(.:format) subjects#new
edit_subject GET /subjects/:id/edit(.:format) subjects#edit
subject GET /subjects/:id(.:format) subjects#show
PATCH /subjects/:id(.:format) subjects#update
PUT /subjects/:id(.:format) subjects#update
DELETE /subjects/:id(.:format) subjects#destroy
No need to specify match ':controller(/:action(/id))', :via => [:get, :post] in the routes. resources :subjects will give u route for all new, create, update, show & delete actions. Try this
Rails.application.routes.draw do
resources :subjects
end
As pulkit21 already stated, you don't need that match in your routes. That works for some specific cases, but in general this is usually hacky code that can be avoided with the correct usage of resource routing.
Removing that line in your routes file will then give you the error "No route matches [POST] "/subjects/1". While I don't fully understand why this happens, I do know that the form_for helper don't need to have the :url parameter set. As a matter of fact, when you use the rails scaffold to generate a controller and views, it uses a single form on a partial file for both the new and edit pages. It can do that because it can detect if a object is a new record (don't have an ID yet, so call CREATE) or is an existing record (already has a database ID, so call PUT to update).
In your case, Rails seems to be misunderstanding the :action => "update" part and instead of routing this to the PUT method (which will call the update method on your controller), is routing it to POST.
Try changing your form_for to this:
<%= form_for(#subject) do |f| %>
It's more elegant, readable and simple, and has the advantage of being able to work for both new and edit forms.
Related
I have a projects.show.html page which shows a project and it's given tasks. The tasks are shown if their completed attribute is set to false (default). I have a method that converts the attribute to true, but when it loads the page, I get an error:
"ActiveRecord::RecordNotFound in ProjectsController#show
Couldn't find Project with 'id'=tasks
def show
#project = Project.find(params[:id])
#task = #project.tasks.build
end
"
Here's my code:
projects_controller
def show
#project = Project.find(params[:id])
#task = #project.tasks.build
end
Tasks_controller
def completed
#task = Task.find(params[:id])
#task.completed = true
#task.save
redirect_to project_path(#project)
end
Projects/show.html.erb
<% if #project.tasks.size > 0 %>
<table class="table">
<tr>
<th>Task</th>
</tr>
<% #project.tasks.each do |task| %>
<tr>
<td><%= task.notes %></td>
<td><% if !task.completed %><%= link_to "Mark Complete", 'tasks/#{:id}/completed' %></td>
<% end %>
<% end %>
<% end %>
</table>
Any help would be appreciated.
Here tasks/#{:id}/completed - you put id as a symbol while you need to pass real id. You should use Rails routes helper instead of tasks/#{:id}/completed and it will make your life easier.
In terminal: rails routes or rake routes.
Find the route you need
Replace your link with something like this link_to('My link', task_complete_path(task.id))
If this not helps you, please reply and provide also your route definition.
First of all, consider defining your routes like this:
resources :projects do
resources :tasks, shallow: true do
member do
patch :completed
end
end
end
(You can read more about nesting resources and adding more RESTful actions in the docs.)
Which will give you:
completed_task PATCH /tasks/:id/completed(.:format) tasks#completed
project_tasks GET /projects/:project_id/tasks(.:format) tasks#index
POST /projects/:project_id/tasks(.:format) tasks#create
new_project_task GET /projects/:project_id/tasks/new(.:format) tasks#new
edit_task GET /tasks/:id/edit(.:format) tasks#edit
task GET /tasks/:id(.:format) tasks#show
PATCH /tasks/:id(.:format) tasks#update
PUT /tasks/:id(.:format) tasks#update
DELETE /tasks/:id(.:format) tasks#destroy
projects GET /projects(.:format) projects#index
POST /projects(.:format) projects#create
new_project GET /projects/new(.:format) projects#new
edit_project GET /projects/:id/edit(.:format) projects#edit
project GET /projects/:id(.:format) projects#show
PATCH /projects/:id(.:format) projects#update
PUT /projects/:id(.:format) projects#update
DELETE /projects/:id(.:format) projects#destroy
Notice that you now have a named path for completed_task that responds to the PATCH HTTP verb.
Then, update app/views/projects/show.html.erb to include:
<% if #project.tasks.any? %>
<table class="table">
<tr>
<th>Task</th>
</tr>
<% #project.tasks.each do |task| %>
<tr>
<td>
<%= task.notes %>
</td>
<td>
<% unless task.completed %>
<%= link_to "Mark Complete", completed_task_path(task), method: :patch %>
<% end %>
</td>
</tr>
<% end %>
</table>
<% end %>
It looks to me like your table is malformed, so I tried to fix it. You may need to fiddle with that.
Your TasksController#completed action is also malformed. You try to redirect to project_path(#project), but you never define #project. It should look more like:
def completed
#task = Task.find(params[:id])
#task.update(completed: true)
redirect_to #task.project
end
This, naturally, assumes you've set up your Task and Project association correctly, something like:
class Task < ActiveRecord::Base
belongs_to :project
end
FYI, I just cloned your projects and added this to views/static/index.html.erb (naturally, '1' is just a dummy ID since I don't have any records in the DB):
<%= link_to "Test", completed_task_path(1), method: :patch %>
Which gave me:
<a rel="nofollow" data-method="patch" href="/tasks/1/completed">Test</a>
When I click on it, I get:
Started PATCH "/tasks/1/completed" for 127.0.0.1 at 2018-07-10 09:28:01 -0700
Processing by TasksController#completed as HTML
Parameters: {"authenticity_token"=>"euLDameHwkrCCMfTsPg5Znk2Mwuh7v6/O2wZFt6zGaRJzE9F1XMgGR1Uz2oYfpeQL//v/L1QtAEo7TDqsphIFw==", "id"=>"1"}
Figured it out, thanks #jvillian for your help.
Instead of using a method in my tasks controller to change the Task.completed attribute (originally a string), I created an enumerable (similar to a boolean in that it's binary) that can be switched from "incomplete" to "complete" whenever the method is called.
app/controllers/tasks_controller:
include ProjectsHelper
class TasksController < ApplicationController
def create
t = Task.new(task_params)
t.save
redirect_to project_path(t.project)
end
def update
t = Task.find(params[:id])
if t.user == current_user
t.update(completion_status: 'complete', completion_date: DateTime.now, completed: true)
t.project.update(last_completed: DateTime.now)
end
redirect_to :back
end
def toggle_status
#task = Task.find(params[:id])
if #task.incomplete?
#task.complete!
elsif #task.complete?
#task.incomplete!
end
redirect_to #task.project
end
private
def task_params
params.require(:task).permit(:user_id, :project_id, :notes)
end
Then for my model:
class Task < ApplicationRecord
enum status: [ :incomplete, :complete ]
belongs_to :user
belongs_to :project
validates :notes, presence: true
scope :completed, -> { where(completed: true) }
def self.completed
Task.completed
end
end
The enum status serves as a binary option, much like a boolean. Formerly a string, I was able to change method to simply 'flip' the value of the enumerable, and write the proper controller action in my project/show:
<% if #project.tasks.any? %>
<table class="table">
<tr>
<th>Task</th>
</tr>
<% #project.tasks.each do |task| %>
<tr>
<td>
<%= task.notes %>
<%= task.status %>
</td>
<td>
<% if !task.id.nil? %>
<%= link_to "Change Status", toggle_status_task_path(task) %>
<% end %>
</td>
</tr>
<% end %>
</table>
<% end %>
I'm trying to update a record with a button, by having and admin user tyoe confirm a record by clicking the confirm submit button with this form, but it would just update the first record in the database, not the specific one. Can i put "hour.id" in the form_for section to make it update the record i want it to?
index.html.erb form view
<% #allhours.each do |hour| %>
<tr id="dashfield">
<td><%= hour.user.first_name + " " +hour.user.last_name %></td>
<td><%= hour.assignment %></td>
<td><%= hour.hours %></td>
<td><%= hour.supervisor %></td>
<td><%= hour.date %></td>
<td><%= link_to "confirm", edit_hour_path(hour.id, :status => 'confirmed')%></td>
</tr>
<% end %>
Controller
def index
#allhours = HourLog.where(status:'pending')
end
def update
#hour = HourLog.find_by(status:'pending')
#hour.update_attribute(update_hour_params)
redirect_to '/dashboard/hours'
end
def edit
#hour = HourLog.find(params[:id])
#hour.update_attributes(update_hour_params)
redirect_to '/dashboard/hours'
end
hour_log model
class HourLog < ActiveRecord::Base
belongs_to :user
end
routes
Rails.application.routes.draw do
root 'welcome#index'
get '/signup' => 'users#new'
resources :users
get '/dashboard/users' => 'users#index'
put '/dashboard/users' => 'users#update'
get '/login' => 'sessions#new'
post '/login' => 'sessions#create'
delete '/logout' => 'sessions#destroy'
get '/dashboard' => 'hours#new'
get '/dashboard/hours' => 'hours#index'
put '/dashboard/hours' => 'hours#update'
resources :hours
Thanks!
This line :
#hour = HourLog.find_by(status:'pending')
will find the first Hourlog that is in pending status. You should pass the hourlog id in the form and use it in the controller
change the line in the routes :
put '/dashboard/hours/:id' => 'hours#update'
in the view :
<%= form_tag dashboard_hours_path(id:hour.id), method: :put do %>
<%= hidden_field_tag :role, :value => 'confirm'%>
<%= submit_tag 'Confirm'%>
<% end %>
in the controller :
#hour = HourLog.find(params[:id])
I created an edit form for my model "Things", but when I submit the form, it returns the error "No route matches [PATCH] "/things"". The weird thing is, the url of the error is http://localhost:3000/things, but I was expecting it to be http://localhost:3000/things/:id, because I wrote redirect_to #thing under the create function. I just defined all my Thing routes with resources :things, so it should have the update path defined. What am I doing wrong?
things_controller:
class ThingsController < ApplicationController
def show
#thing = Thing.find(params[:id])
#category_things = CategoryThing.all
#thing.categories.build
#thing.things.build
#related_things = RelatedThing.all
end
def index
end
def new
#thing = Thing.new
#things = Thing.all
end
def create
#thing = Thing.new(thing_params)
if #thing.save
redirect_to #thing
else
render 'new'
end
end
def edit
#thing = Thing.find(params[:id])
end
def update
#thing = Thing.find(params[:id])
if #thing.update_attributes(thing_params)
flash[:success] = "Thing updated"
redirect_to #thing
else
render 'edit'
end
end
private
def thing_params
params.require(:thing).permit(:name, :image_path, :avatar)
end
end
things/edit.html.erb:
<h1>Edit <%= #thing.name %></h1>
<p>
<%= form_for #thing, :url => things_path, :html => { :multipart => true } do |f| %>
<%= f.text_field :name, :placeholder => "Name of the thing" %>
<br>
<%= f.label :categories_the_thing_belongs_to %>
<%= f.collection_select :categories, Category.all, :id, :name %>
<br>
<%= f.label :related_things %>
<%= f.collection_select :related_things, Thing.all, :id, :name %>
<br>
<%= f.label :display_picture %>
<%= f.file_field :avatar %>
<br>
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
</p>
Output of rake routes
Prefix Verb URI Pattern Controller#Action
ratings_new GET /ratings/new(.:format) ratings#new
down_votes_new GET /down_votes/new(.:format) down_votes#new
thing_new GET /thing/new(.:format) thing#new
good_comments_new GET /good_comments/new(.:format) good_comments#new
good_comments_show GET /good_comments/show(.:format) good_comments#show
bad_comments_new GET /bad_comments/new(.:format) bad_comments#new
related_things_new GET /related_things/new(.:format) related_things#new
things_new GET /things/new(.:format) things#new
category_things_new GET /category_things/new(.:format) category_things#new
thing_ratings_new GET /thing_ratings/new(.:format) thing_ratings#new
category_ratings_new GET /category_ratings/new(.:format) category_ratings#new
subjects GET /subjects(.:format) subjects#index
POST /subjects(.:format) subjects#create
new_subject GET /subjects/new(.:format) subjects#new
edit_subject GET /subjects/:id/edit(.:format) subjects#edit
subject GET /subjects/:id(.:format) subjects#show
PATCH /subjects/:id(.:format) subjects#update
PUT /subjects/:id(.:format) subjects#update
DELETE /subjects/:id(.:format) subjects#destroy
subjects_show GET /subjects/show(.:format) subjects#show
subject_things_new GET /subject_things/new(.:format) subject_things#new
categories GET /categories(.:format) categories#index
POST /categories(.:format) categories#create
new_category GET /categories/new(.:format) categories#new
edit_category GET /categories/:id/edit(.:format) categories#edit
category GET /categories/:id(.:format) categories#show
PATCH /categories/:id(.:format) categories#update
PUT /categories/:id(.:format) categories#update
DELETE /categories/:id(.:format) categories#destroy
categories_results GET /categories/results(.:format) categories#results
subjects_new GET /subjects/new(.:format) subjects#new
root GET / home_page#home
all_things_new GET /all/things/new(.:format) things#new
all_allthings GET /all/allthings(.:format) all#allthings
thing_good_comments GET /things/:thing_id/good_comments(.:format) good_comments#index
POST /things/:thing_id/good_comments(.:format) good_comments#create
new_thing_good_comment GET /things/:thing_id/good_comments/new(.:format) good_comments#new
edit_thing_good_comment GET /things/:thing_id/good_comments/:id/edit(.:format) good_comments#edit
thing_good_comment GET /things/:thing_id/good_comments/:id(.:format) good_comments#show
PATCH /things/:thing_id/good_comments/:id(.:format) good_comments#update
PUT /things/:thing_id/good_comments/:id(.:format) good_comments#update
DELETE /things/:thing_id/good_comments/:id(.:format) good_comments#destroy
thing_bad_comments GET /things/:thing_id/bad_comments(.:format) bad_comments#index
POST /things/:thing_id/bad_comments(.:format) bad_comments#create
new_thing_bad_comment GET /things/:thing_id/bad_comments/new(.:format) bad_comments#new
edit_thing_bad_comment GET /things/:thing_id/bad_comments/:id/edit(.:format) bad_comments#edit
thing_bad_comment GET /things/:thing_id/bad_comments/:id(.:format) bad_comments#show
PATCH /things/:thing_id/bad_comments/:id(.:format) bad_comments#update
PUT /things/:thing_id/bad_comments/:id(.:format) bad_comments#update
DELETE /things/:thing_id/bad_comments/:id(.:format) bad_comments#destroy
thing_ratings GET /things/:thing_id/ratings(.:format) ratings#index
POST /things/:thing_id/ratings(.:format) ratings#create
new_thing_rating GET /things/:thing_id/ratings/new(.:format) ratings#new
edit_thing_rating GET /things/:thing_id/ratings/:id/edit(.:format) ratings#edit
thing_rating GET /things/:thing_id/ratings/:id(.:format) ratings#show
PATCH /things/:thing_id/ratings/:id(.:format) ratings#update
PUT /things/:thing_id/ratings/:id(.:format) ratings#update
DELETE /things/:thing_id/ratings/:id(.:format) ratings#destroy
thing_up_votes GET /things/:thing_id/up_votes(.:format) up_votes#index
POST /things/:thing_id/up_votes(.:format) up_votes#create
new_thing_up_vote GET /things/:thing_id/up_votes/new(.:format) up_votes#new
edit_thing_up_vote GET /things/:thing_id/up_votes/:id/edit(.:format) up_votes#edit
thing_up_vote GET /things/:thing_id/up_votes/:id(.:format) up_votes#show
PATCH /things/:thing_id/up_votes/:id(.:format) up_votes#update
PUT /things/:thing_id/up_votes/:id(.:format) up_votes#update
DELETE /things/:thing_id/up_votes/:id(.:format) up_votes#destroy
things GET /things(.:format) things#index
POST /things(.:format) things#create
new_thing GET /things/new(.:format) things#new
edit_thing GET /things/:id/edit(.:format) things#edit
thing GET /things/:id(.:format) things#show
PATCH /things/:id(.:format) things#update
PUT /things/:id(.:format) things#update
DELETE /things/:id(.:format) things#destroy
things_show GET /things/show(.:format) things#show
things_results GET /things/results(.:format) things#results
things_random GET /things/random(.:format) things#random
web_console /console WebConsole::Engine
Routes for WebConsole::Engine:
root GET / web_console/console_sessions#index
input_console_session PUT /console_sessions/:id/input(.:format) web_console/console_sessions#input
pending_output_console_session GET /console_sessions/:id/pending_output(.:format) web_console/console_sessions#pending_output
configuration_console_session PUT /console_sessions/:id/configuration(.:format) web_console/console_sessions#configuration
console_sessions GET /console_sessions(.:format) web_console/console_sessions#index
POST /console_sessions(.:format) web_console/console_sessions#create
new_console_session GET /console_sessions/new(.:format) web_console/console_sessions#new
edit_console_session GET /console_sessions/:id/edit(.:format) web_console/console_sessions#edit
console_session GET /console_sessions/:id(.:format) web_console/console_sessions#show
PATCH /console_sessions/:id(.:format) web_console/console_sessions#update
PUT /console_sessions/:id(.:format) web_console/console_sessions#update
DELETE /console_sessions/:id(.:format) web_console/console_sessions#destroy
just remove the :url => things_path and use:
<%= form_for #thing, :html => { :multipart => true } do |f| %>
The form_for helper automatically generates the proper resfull endpoint if using ressourcefull routes.
Depending on #thing being persisted? or a new_record? it the endpoint will be :create or :update
I'm doing an online tutorial and was tasked with implementing a comment resource that is nested under a post resource, which in turn is under a topic resource. I've figured out all of the steps of the exercise except getting the 'comment create' form to show up on post#show. I have been trying for several hours to fix it but keep getting the following error: undefined method "model_name" for NilClass:Class. I have no idea what it is referring to by model_name and in my desperation I even looked at the tutorial's code on GitHub, but I still can't see where I'm making the mistake.
My form is in a partial and the error points to the first line, so I'll paste that code here first:
<%= form_for [topic, post, comment] do |f| %>
<div class="controls">
<%= f.text_area :body, rows: 8 %>
</div>
<div class="control-group">
<div class="controls">
<%= f.submit "Add Comment", class: 'btn' %>
</div>
</div>
<% end %>
I'll post my routes so you can see the nesting:
X::Application.routes.draw do
devise_for :users
resources :topics do
resources :posts, except: [:index] do
resources :comments, only: [:create]
end
end
match "about" => 'welcome#about', via: :get
root to: 'welcome#index'
end
Here is my Comments controller:
class CommentsController < ApplicationController
def new
end
def create
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:post_id])
#comment = current_user.comments.build(params[:comment])
#comment.post = #post
if #comment.save
flash[:notice] = "Comment was saved."
redirect_to #post
else
flash[:error] = "Error! Try again."
render :new
end
end
end
Here is my post#show view (form should be rendering at the bottom):
<h1><%= markdown #post.title %></h1>
<div class="row">
<div class="span8">
<small>
<%= image_tag(#post.user.avatar.tiny.url) if #post.user.avatar? %>
submitted <%= time_ago_in_words(#post.created_at) %> ago by
<%= #post.user.name %>
</small>
<br><br>
<p><%= image_tag(#post.image.url) if #post.image? %></p>
<p><%= markdown #post.body %></p>
</div>
<div class="span2">
<% if can? :edit, #post %>
<%= link_to "Edit Post", edit_topic_post_path(#topic,#post), class: 'btn btn-small' %>
<% end %>
</div>
</div>
<br><br>
<h4>Comments</h4>
<%= render #comments %>
<br>
<%= render :template => "/comments/_form.html.erb", locals: { topic: #topic, post: #post, comment: #comment } %>
I would be SO grateful if anyone could help me with this problem. And let me know if there's any info I should add. Thank you!
Generally from what i have read its not recommended using 3 level nested resources. Could you link to the tutorial you are following?
Anyhow I would suggest using shallow on your routes instead.
resources :topics, shallow: true do
resources :posts, except: [:index], shallow: true do
resources :comments, only: [:create]
end
end
Will give you the following resources, which in return will make it easier to create correct forms in your view.
post_comments POST /posts/:post_id/comments(.:format) comments#create
topic_posts POST /topics/:topic_id/posts(.:format) posts#create
new_topic_post GET /topics/:topic_id/posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
topics GET /topics(.:format) topics#index
POST /topics(.:format) topics#create
new_topic GET /topics/new(.:format) topics#new
edit_topic GET /topics/:id/edit(.:format) topics#edit
topic GET /topics/:id(.:format) topics#show
PATCH /topics/:id(.:format) topics#update
PUT /topics/:id(.:format) topics#update
DELETE /topics/:id(.:format) topics#destroy
Now you should only have to send post_id to your comments form. Read more here I haven't worked much with 3 level nesting but this should give you an idea of how you could make it easier for yourself.
EDIT:
In the create action you should build the comment using #post and then set the user to current_user.
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(params[:comment])
#comment.user = current_user
if #comment.save
flash[:notice] = "Comment was saved."
redirect_to #post
else
flash[:error] = "Error! Try again."
render :new
end
end
And now no need for #topic
<%= render :template => "/comments/_form.html.erb", locals: { post: #post, comment: #comment } %>
Add '#comment = Comment.new' to the "show" action of the PostController. It had been defined only in the CommentController "create" action.
I am in the process of still learning Rails 3 but routes are driving me crazy. I am trying to use a namespace to separate an administration section of the site. Problem is that some things in the namespace simply don't work and also route to the wrong place. For example using rails generated routes by specifying a resource the view points to the wrong route when passed an object so the edit form won't work.
Links with link_to don't work either even when the route does exist it says it doesn't. Firstly here is the namespaced routes output from rake routes.
namespace :admin do
resources :users
end
admin_users GET /admin/users(.:format) {:action=>"index", :controller=>"admin/users"}
POST /admin/users(.:format) {:action=>"create", :controller=>"admin/users"}
new_admin_user GET /admin/users/new(.:format) {:action=>"new", :controller=>"admin/users"}
edit_admin_user GET /admin/users/:id/edit(.:format) {:action=>"edit", :controller=>"admin/users"}
admin_user PUT /admin/users/:id(.:format) {:action=>"update", :controller=>"admin/users"}
DELETE /admin/users/:id(.:format) {:action=>"destroy", :controller=>"admin/users"}
Controller:
class Admin::UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def edit
#user = User.find(params[:id])
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to(#user, :notice => 'User was successfully created.')
else
render :action => "new"
end
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
redirect_to(admin_users_path, :notice => 'User was successfully updated.')
else
render :action => "edit"
end
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to(admin_users_path)
end
end
Example view: index.html.erb listing all users
<h1>Listing users</h1>
<table>
<% for user in #users %>
<tr>
<td><%= user.id %></td>
<td><%= user.username %></td>
<td><%= user.email %></td>
<td><%= link_to 'Show', #user %></td>
<td><%= link_to 'Edit', edit_admin_user_path(user) %></td>
<td><%= link_to 'Destroy', admin_user_path, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New User', new_admin_user_path %>
Using the edit view is also having a problem. The edit form should point to the update route but does not. Instead it points to the edit route (basically itself) when only being passed a User object. From what I have been reading using an object in forms is the recommended way but this cant be a good thing if it does not work.
I get this error on listing all users page.
No route matches {:action=>"update", :controller=>"admin/users"}
Extracted source (around line #17):
17: <td><%= link_to 'Destroy', admin_user_path, :confirm => 'Are you sure?', :method => :delete %></td>
I am so trying to persevere but this is driving me loopy. FYI: Yes I know there are authentication frameworks out there but I am trying to make one from scratch. This is a learning experience and as such just using gems and plugins willy nilly is not the way to go in my opinion.
Thank you
Onyth
You're missing the id in the delete link
Try with
<td><%= link_to 'Destroy', admin_user_path(user), :confirm => 'Are you sure?', :method => :delete %></td>
(changed admin_user_path to admin_user_path(user) as the link)
If you do a rake routes you would see something like this:
admin_users GET /admin/users(.:format) {:controller=>"admin/users", :action=>"index"}
POST /admin/users(.:format) {:controller=>"admin/users", :action=>"create"}
new_admin_user GET /admin/users/new(.:format) {:controller=>"admin/users", :action=>"new"}
edit_admin_user GET /admin/users/:id/edit(.:format) {:controller=>"admin/users", :action=>"edit"}
admin_user GET /admin/users/:id(.:format) {:controller=>"admin/users", :action=>"show"}
PUT /admin/users/:id(.:format) {:controller=>"admin/users", :action=>"update"}
DELETE /admin/users/:id(.:format) {:controller=>"admin/users", :action=>"destroy"}
admin_pages GET /admin/pages(.:format) {:controller=>"admin/pages", :action=>"index"}
POST /admin/pages(.:format) {:controller=>"admin/pages", :action=>"create"}
new_admin_page GET /admin/pages/new(.:format) {:controller=>"admin/pages", :action=>"new"}
edit_admin_page GET /admin/pages/:id/edit(.:format) {:controller=>"admin/pages", :action=>"edit"}
admin_page GET /admin/pages/:id(.:format) {:controller=>"admin/pages", :action=>"show"}
PUT /admin/pages/:id(.:format) {:controller=>"admin/pages", :action=>"update"}
DELETE /admin/pages/:id(.:format) {:controller=>"admin/pages", :action=>"destroy"}
So you can derive
admin_user_path
which would be the same as
user_path
Then you would pass the #user in admin_user_path like so:
admin_user_path(#user)
The :method should then call the destroy method instead of going to the show method automatically! :)
To get the form_for working, I found the following resource: http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for
Under the form_for section, they explain namespace routing with form_for as:
For namespaced routes, like admin_post_url:
<%= form_for([:admin, #post]) do |f| %>
...
<% end %>
For information regarding rake routes check out: http://guides.rubyonrails.org/command_line.html#rake-is-ruby-make then under section 2.4.9 Miscellaneous Tasks they explain rake --tasks shows you various rake commands that you can use and rake routes shows you route paths available.
Hope this helps!