Rails Import CSV - No Route Matches - ruby-on-rails

I'm very new to Rails. I'm currently trying to import data from an csv file into my rails application. However, when I followed examples and guides online, I got the error: No route matches {:action=>"import_csv", :controller=>"lists"} I've already added it in my routes.rb though. Can anyone help me check what is wrong if my codes to cause to 'no route matches' error? Below are my files:
lists_controller.rb
def import_csv
require 'fastercsv'
respond_to do |format|
#csv=params[:file].read
#n=0
#parsed_file = CSV.parse(csv)
#parsed_file.each do |row|
#user_new = User.new
#user_new.first_name = row[0]
#user_new.last_name = row[1]
#user_new.email = row[2]
#user_new.address = row[3]
#user_new.city = row[4]
#user_new.state = row[5]
#user_new.zip = row[6]
#user_new.country = row[7]
#user_new.notes = row[8]
#user_new.birthday = row[9]
#user_new.home_number = row[10]
#user_new.mobile_number = row[11]
#user_new.list_id = list_id
#user_new.save
#n=#n+1
GC.start if n%50==0
flash[:notice] = "CSV Imported Successfully, with #{n} records"
end
format.html { redirect_to lists_url }
format.json { head :no_content }
end
end
app/views/lists/show.html.erb
<%= form_for(:list, :url => list_import_csv_path, :html => {:multipart => true}) do |f| %>
<table>
<tr>
<td><label for="dump_file">Select a CSV File :</label></td>
<td ><%= file_field_tag :file %></td>
</tr>
<tr>
<td colspan='2'><%= submit_tag 'Submit' %></td>
</tr>
</table>
<% end %>
routes.rb
resources :lists do
get 'import_csv'
#match '/import_csv/:id' => 'lists#import_csv', :as => :import_csv
end
rake routes
identities GET /identities(.:format) identities#index
POST /identities(.:format) identities#create
new_identity GET /identities/new(.:format) identities#new
edit_identity GET /identities/:id/edit(.:format) identities#edit
identity GET /identities/:id(.:format) identities#show
PUT /identities/:id(.:format) identities#update
DELETE /identities/:id(.:format) identities#destroy
newsletter_cancel GET /newsletters/:newsletter_id/cancel(.:format) newsletters#cancel
newsletters GET /newsletters(.:format) newsletters#index
POST /newsletters(.:format) newsletters#create
new_newsletter GET /newsletters/new(.:format) newsletters#new
edit_newsletter GET /newsletters/:id/edit(.:format) newsletters#edit
newsletter GET /newsletters/:id(.:format) newsletters#show
PUT /newsletters/:id(.:format) newsletters#update
DELETE /newsletters/:id(.:format) newsletters#destroy
list_import_csv GET /lists/:list_id/import_csv(.:format) lists#import_csv
lists GET /lists(.:format) lists#index
POST /lists(.:format) lists#create
new_list GET /lists/new(.:format) lists#new
edit_list GET /lists/:id/edit(.:format) lists#edit
list GET /lists/:id(.:format) lists#show
PUT /lists/:id(.:format) lists#update
DELETE /lists/:id(.:format) lists#destroy
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy

Your form is submitted with a POST, while the route is for a GET. Either pass :method => :get to the form_for helper, or change your route to post (I would prefer the former though, since you're requesting data, not changing anything on the server).
To specify GET method for a form, you would do
<%= form_for (:list, :url => list_import_csv_path, :method => :get, :html => {:multipart => true}) do |f| %>
I'm also not sure if it's a good idea to force start garbage collection - it'd kill your performance if it kicks in while processing requests. Leftover objects should get garbage collected automatically.
I'd also extract the User export part (probably into a static method on the User model):
require 'faster_csv'
class User < ActiveRecord::Base
...
def self.import_from_csv(file)
CSV.parse(file).each do |row|
u = User.new(:first_name => row[0], :last_name => row[1] ...etc)
return false if !u.save
end
end
end
Then, in the controller:
def import_csv
respond_to do |format|
if !User.import_from_csv(params[:file])
format.html { render :show, :error => "Some error here" }
format.json { render :json => "Some error here", :status => :unprocessable_entity }
else
format.html { redirect_to lists_url, :notice => "Import successful!" }
format.json { :head => :ok }
end
end
end

Use post instead of get in your config/routes.rb.

Related

Destroy Action Acting Unusual

The application has: Clients, which has and belongs to many ActionItems, which has and belongs to many Clients. A user, chooses a client (a client they have as a customer), and adds action items (to do's) to that client. -- Like: User creates => "Email client about X topic," for client: Crayola LLC.
I've been instructed to nest resources like so, in routes:
resources :clients do
resources :action_items
end
So that I can get a URL like:
-http://localhost:3000/clients/42/action_items/11
To display the action items for a specific client.
However - deleting action items for that client, doesn't work. It's been trying to redirect me to the destroy action, on which I get:
undefined local variable or method `clients_action_items' for # <ActionItemsController:0x007febd0edf800>
Prior to this, the delete link, which uses the destroy action, was attempting to redirect me to the show page, on which I was getting:
No route matches [POST] "/clients/42/action_items/1"
Then I added: post '/clients/:client_id/action_items/:id' => 'action_items#destroy' to the routes file. (and now I get the undefined local variable or method clients_action_items' error.
Routes:
Rails.application.routes.draw do
get 'users/index'
get 'users/new'
get 'users/edit'
get 'users/delete'
get 'users/create'
patch 'users/create'
patch 'users/update'
get 'clients/index'
get 'clients/new'
get 'clients/edit'
get 'clients/delete' => 'clients#delete'
get 'clients/create'
patch 'clients/create'
patch 'clients/update'
post '/clients/:client_id/action_items/:id' => 'action_items#destroy'
get 'login', :to => "access#index"
resources :action_items
#/clients/13/action_items
resources :clients do
resources :action_items
end
#get 'home/index'
#get 'home/edit'
#
#get 'home/delete'
#get 'home/show'
root 'home#index'
#define, below **, is the URL we named categories/index. It is now localhost:3000/define
#get 'index' => 'questions#index'
#get 'questions/edit'
#get 'new' => 'questions#new'
#get 'questions/delete'
#post 'questions/destroy'
#get 'questions/show'
#post 'create' => 'questions#create'
match ':controller(/:action(/:id))', :via => [:get, :post]
# end
end
Action Items Controller:
class ActionItemsController < ApplicationController
# before_action :get_owner
def index
#action_items = ActionItem.all
#client = Client.find(params[:client_id])
end
def new
#action_items = ActionItem.new
# #action_items_client = #client.action_items.new
#client = Client.find(params[:client_id])
end
def create
# #action_item = ActionItem.new(action_items_params)
# if #action_item.save
# redirect_to(:action => 'show', :id => #action_item.id)
# #renders client individual page
# else
# redirect_to(:action => 'new')
# end
#client = Client.find(params[:client_id])
#action_item_client = #client.action_items.new(action_items_params)
if #action_item_client.save
redirect_to(:action => 'show', :id => #action_item_client.id, :client_id => #client.id)
else
redirect_to(:action => 'new')
end
end
def edit
#action_item = ActionItem.find(params[:id])
end
def update
#action_item = ActionItem.find(params[:id])
if #action_item.update_attributes(action_items_params)
redirect_to(:controller => 'action_items', :action => 'show', :id => #action_item.id)
flash[:notice] = "Updated"
else
render 'new'
end
end
def show
#client = Client.find(params[:id])
#action_item = ActionItem.find(params[:action_item_id])
end
def action_clients
#action_clients = ActionItem.Client.new
end
def delete
#action_item = #client.action_items.find(params[:client_id])
end
def destroy
# #action_items = #client.action_items.find(params[:id]).destroy
# redirect_to(:controller => 'action_items', :action => 'index')
item = clients_action_items.find(params[:client_id])
item.destroy
if params[:client_id]
redirect_to clients_action_items_path(params[:client_id])
else
redirect_to clients_action_items_path
end
end
private
def action_items_params
params.require(:action_item).permit(:purpose, :correspondence_method, :know_person, :contact_name_answer, :additional_notes)
end
# private
# def get_owner
# if params[:client_id].present?
# #owner = user.clients.find(params[:client_id])
# else
# #owner = user
# end
# end
end
Index view from which I am deleting an action item:
<%= link_to('New Action Item', :controller => 'action_items', :action => 'new') %></br>
<ol><% #action_items.each do |list| %>
<li>
Action Item for <%= #client.name %> is: <strong><%= list.correspondence_method %></strong> Client, about:
<strong><%= list.purpose %> </strong></li>
And you created some additional notes: <strong><%= list.additional_notes %></strong></br></br>
-- Crud Actions -- </br>
<%= link_to('New Action Item', :controller => 'action_items', :action => 'new') %></br>
<%= link_to('Edit Action Item', :controller => 'action_items', :action => 'edit', :id => list.id) %></br>
<%= link_to('Show Individual', :controller => 'action_items', :action => 'show', :id => list.id) %></br>
<%= button_to('Delete Action Item', :controller => 'action_items', :action => 'destroy', :id => list.id) %></br>
<h2> new delete </h2>
</br></br>
<% end %></ol>
I have created the foreign key columns in a migration file with a join table called: action_items_clients:
class CreateActionItemsClients < ActiveRecord::Migration
def change
create_table :action_items_clients, :id => false do |t|
t.integer :action_item_id
t.integer :client_id
end
end
end
-New to rails. Please excuse dirty code. What is wrong here? Why the destroy link issues? Why was the destroy link redirecting to show before, and giving me both routing and ID errors?
Thanks for your time.
*** EDIT ****
Rake routes output:
Prefix Verb URI Pattern Controller#Action
users_index GET /users/index(.:format) users#index
users_new GET /users/new(.:format) users#new
users_edit GET /users/edit(.:format) users#edit
users_delete GET /users/delete(.:format) users#delete
users_create GET /users/create(.:format) users#create
PATCH /users/create(.:format) users#create
users_update PATCH /users/update(.:format) users#update
clients_index GET /clients/index(.:format) clients#index
clients_new GET /clients/new(.:format) clients#new
clients_edit GET /clients/edit(.:format) clients#edit
clients_delete GET /clients/delete(.:format) clients#delete
clients_create GET /clients/create(.:format) clients#create
PATCH /clients/create(.:format) clients#create
clients_update PATCH /clients/update(.:format) clients#update
DELETE /clients/:client_id/action_items/:id(.:format) action_items#destroy
login GET /login(.:format) access#index
action_items GET /action_items(.:format) action_items#index
POST /action_items(.:format) action_items#create
new_action_item GET /action_items/new(.:format) action_items#new
edit_action_item GET /action_items/:id/edit(.:format) action_items#edit
action_item GET /action_items/:id(.:format) action_items#show
PATCH /action_items/:id(.:format) action_items#update
PUT /action_items/:id(.:format) action_items#update
DELETE /action_items/:id(.:format) action_items#destroy
client_action_items GET /clients/:client_id/action_items(.:format) action_items#index
POST /clients/:client_id/action_items(.:format) action_items#create
new_client_action_item GET /clients/:client_id/action_items/new(.:format) action_items#new
edit_client_action_item GET /clients/:client_id/action_items/:id/edit(.:format) action_items#edit
client_action_item GET /clients/:client_id/action_items/:id(.:format) action_items#show
PATCH /clients/:client_id/action_items/:id(.:format) action_items#update
PUT /clients/:client_id/action_items/:id(.:format) action_items#update
DELETE /clients/:client_id/action_items/:id(.:format) action_items#destroy
clients GET /clients(.:format) clients#index
POST /clients(.:format) clients#create
new_client GET /clients/new(.:format) clients#new
edit_client GET /clients/:id/edit(.:format) clients#edit
client GET /clients/:id(.:format) clients#show
PATCH /clients/:id(.:format) clients#update
PUT /clients/:id(.:format) clients#update
DELETE /clients/:id(.:format) clients#destroy
root GET / home#index
GET|POST /:controller(/:action(/:id))(.:format) :controller#:action
It seems you are trying to destroy an object using a POST request.
No route matches [POST] "/clients/42/action_items/1"
Did you try a DELETE request?
delete '/clients/:client_id/action_items/:id' => 'action_items#destroy'
You can read further about CRUD (Create, Read, Update, Delete) operations here
Also, can you run rake:routes and post the output here? That will help figure out what routes are actually being generated.
EDIT
So, as you can see from the output of rake:routes there is a LOT of duplication. You basically have three models, User, Client and ActionItems with basic CRUD and one login.
Rake file:
Rails.application.routes.draw do
get 'login', :to => "access#index"
resources :users
resources :action_items
resources :clients do
member do
get :action_items
end
end
root 'home#index'
end
Client and ActionItems have a many-to-many relation. If it was a one-to-many ie many ActionItems belong to only one Client then it would have been better to nest the resources.
To show all action items of a client you only need one extra method in client controller.
Clients Controller:
def show
#client = Client.find(params[:id])
end
def action_items
#list_action_items = #client.action_items
end
Action Items Controller:
#Will list all action_items irrespective of which clients they belong to
def index
#action_items = ActionItem.all
end
#For creating a new action item,
def new
#action_item = ActionItem.new
#You can render a form with dropdown here with Client.all to assign the new action_item to a client
end
def create
#action_item = ActionItem.new(action_items_params)
if #action_item.save
redirect_to(:action => 'show', :id => #action_item.id)
#renders client individual page
else
redirect_to(:action => 'new')
end
end
def edit
#action_item = ActionItem.find(params[:id])
end
def update
if #action_item.update_attributes(action_items_params)
flash[:notice] = "Updated"
redirect_to(:controller => 'action_items', :action => 'show', :id => #action_item.id)
else
render 'new'
end
end
def show
#action_item = ActionItem.find(params[:id])
end
def destroy
#action_item.destroy
flash[:notice] = "Action Item has been deleted."
redirect_to action_items_path
end
I have tried to simplify the structure here. If you want to perform tasks like deleting all action items of a client from the index/list page of all clients, you can define a method destroy_many in the ActionItems controller which takes client_id as argument, queries all action items and deletes them.
You don't need separate ClientActionItem controller/routes.
Also, if you want to continue with nested routes,
try
<%= button_to('Delete Action Item', client_action_item_path(#client.id, list.id), method: :delete) %></br>
The nested route requires two arguments. The first is client.id and second the action_item id.
This should work, but un-tested. I am not sure of your intentions, but I would use a link_to with a class of button personally.
<%= button_to('Delete Action Item', client_action_item_path(#client, list), method: :delete) %></br>

Rails Route adding dot with Devise

My rails app is adding a dot/period "." into the route when trying to browse to a devise gem user's profile.
routes.rb:
devise_for :users, :controllers => { :registrations => "registrations" }
(Basically using routes to allow for some custom functions - it should be still using the default devise routing paths.
Rake routes output:
user_registration POST /users(.:format) registrations#create
new_user_registration GET /users/sign_up(.:format) registrations#new
edit_user_registration GET /users/edit(.:format) registrations#edit
Link in view:
<%= link_to 'Edit', edit_user_registration_path(user) %>
Where user is defined in a .each loop.
Outputted Link in URL looks like:
http://localhost:3000/users/edit.2
My goal is to have a link to edit any user's profile (permissions controlled outside these items of course).
I "think" my problem is the routes.rb and not specifying the path correctly there. I think it should be something that would have a rake routes that includes an :id parameter.
Thanks for the help!
That's normal routes's devise, registrations#edit is for edit current signed-in user, If you want to CRUD interface for users (I think you want to editing a user), you can add another controller (e.g users_controller.rb) and make some action , example for controller :
def edit
#user = User.find(params[:id])
end
def update
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to some_path, notice: 'Updated.' }
format.json { head :no_content }
else
format.html {
flash[:alert] = "Something wrong"
render :action => :edituser
}
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
On your routes.rb you can following like this
scope '/user' do
match '/edit/:id' => 'users#edit', :as => :edit_user
put '/update/:id' => 'users#update', :as => :update_user
end
And links on each section looks like :
<%= link_to 'Edit', edit_user_path(user) %>
references :
How To: Manage users through a CRUD interface
CRUD Devise Example
I think Devise's edit_user_registration_path uses current_user internally, so you shouldn't need the (user) in your link_to

having trouble getting form to submit to the correct route

When submitting my form (_reply_form.html.erb) I get this error:
Routing Error
No route matches [POST] "/responses/replies/4"
Try running rake routes for more information on available routes.
This is how my architecture is set up: Offering has many Responses. Response has many Replies.
I know I need the form to submit to this route, but I can't get it to do that:
response_replies POST /responses/:response_id/replies(.:format) replies#create
_reply_form.html.erb:
<%= form_for(#reply, :url => response_reply_path([#response, #reply])) do |f| %>
<%= render 'common/form_errors', object: #reply %>
<%= f.label :body, "Your Reply" %>
<%= f.text_area(:body, :rows => 10, :class => "field span6") %>
<%= f.submit "Post Reply", :class => "block" %>
<% end %>
_response.html.erb:
<%= render 'replies/reply_form', {:response => #response, :reply => #reply} %>
offerings/show.html.erb:
<% if #offering.responses.any? %>
<%= render #offering.responses %>
<% else %>
<p>This offering has no responses yet.</p>
<% end %>
responses_controller.rb:
class ResponsesController < ApplicationController
before_filter :auth, only: [:create]
def show
#offering = Offering.new
#response = Response.new
#reply = Reply.new
end
def create
#offering = Offering.find(params[:offering_id])
# now that we have our offering we use it to
# build a response with it
#response = #offering.responses.build(params[:response])
# now we get the user who posted the response
#response.user = current_user
if #response.save
flash[:success] = 'your response has been posted!'
redirect_to #offering
else
#offering = Offering.find(params[:offering_id])
render 'offerings/show'
end
end
end
routes.rb:
resources :offerings, except: [:new] do
# makes it easier for us to display
# forms for responses on the offering show page
# allows us to have access to the
# offering that the response is associated to
resources :responses, only: [:create]
end
resources :responses, except: [:new] do
resources :replies, only: [:create]
end
rake routes produces this:
root / dashboard#index
users POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
sessions POST /sessions(.:format) sessions#create
new_session GET /sessions/new(.:format) sessions#new
need_applicants GET /needs/:need_id/applicants(.:format) applicants#index
POST /needs/:need_id/applicants(.:format) applicants#create
new_need_applicant GET /needs/:need_id/applicants/new(.:format) applicants#new
edit_need_applicant GET /needs/:need_id/applicants/:id/edit(.:format) applicants#edit
need_applicant GET /needs/:need_id/applicants/:id(.:format) applicants#show
PUT /needs/:need_id/applicants/:id(.:format) applicants#update
DELETE /needs/:need_id/applicants/:id(.:format) applicants#destroy
needs GET /needs(.:format) needs#index
POST /needs(.:format) needs#create
edit_need GET /needs/:id/edit(.:format) needs#edit
need GET /needs/:id(.:format) needs#show
PUT /needs/:id(.:format) needs#update
DELETE /needs/:id(.:format) needs#destroy
offering_responses POST /offerings/:offering_id/responses(.:format) responses#create
offerings GET /offerings(.:format) offerings#index
POST /offerings(.:format) offerings#create
edit_offering GET /offerings/:id/edit(.:format) offerings#edit
offering GET /offerings/:id(.:format) offerings#show
PUT /offerings/:id(.:format) offerings#update
DELETE /offerings/:id(.:format) offerings#destroy
response_replies POST /responses/:response_id/replies(.:format) replies#create
responses GET /responses(.:format) responses#index
POST /responses(.:format) responses#create
edit_response GET /responses/:id/edit(.:format) responses#edit
response GET /responses/:id(.:format) responses#show
PUT /responses/:id(.:format) responses#update
DELETE /responses/:id(.:format) responses#destroy
register /register(.:format) users#new
login /login(.:format) sessions#new
/offerings(.:format) offerings#index
/needs(.:format) needs#index
dashboard /dashboard(.:format) dashboard#index
contact /contact(.:format) contact#index
your_offerings /your_offerings(.:format) offerings#your_offerings
your_needs /your_needs(.:format) needs#your_needs
search /search(.:format) offerings#search
logout DELETE /logout(.:format) sessions#destroy
-- Original question
This should work for your form_for
<%= form_for([#response, #reply], :url => response_reply_path do |f| %>
-- Second part of your question route matches {:action=>"show", :controller=>"replies"}
I don't see anything wrong in your code, it's maybe in a part of your code you did not paste? Try to search for a link_to that would be corresponding
-- Bonus
Also you should not need to write your render with local variables, the controller instance variables #response and #reply will automatically be present in your partial
<%= render 'replies/reply_form' %>
# #response and #reply are automatically forwarded to all your views and partials
Off course if you are using response and reply in your partial you can rename them to #response and #reply respectively

Add Edit and Delete feature in comment polymorphic-association-revised posts

I read this http://railscasts.com/episodes/154-polymorphic-association-revised posts and implement it as it have. But i want to add edit and delete features also in this tuotorial.
I have comments_controller.rb is like this
class CommentsController < ApplicationController
before_filter :load_commentable
def index
#comments = #commentable.comments
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(params[:comment])
if #comment.save
redirect_to #commentable, notice: "Comment created."
else
render :new
end
end
private
def load_commentable
resource, id = request.path.split('/')[1, 2]
#commentable = resource.singularize.classify.constantize.find(id)
end
# def load_commentable
# klass = [Article, Photo, Event].detect { |c| params["#{c.name.underscore}_id"] }
# #commentable = klass.find(params["#{klass.name.underscore}_id"])
# end
end
my _comments.html.erb as given is like this
<div id="comments">
<% #comments.each do |comment| %>
<div class="comment">
<%= simple_format comment.content %>
</div>
<% end %>
</div>
my routes is like this
Blog::Application.routes.draw do
resources :articles do
resources :comments
end
resources :photos do
resources :comments
end
resources :events do
resources :comments
end
resources :comments
root to: 'articles#index'
end
My rake routes is like this
article_comment GET /articles/:article_id/comments/:id(.:format) comments#show
PUT /articles/:article_id/comments/:id(.:format) comments#update
DELETE /articles/:article_id/comments/:id(.:format) comments#destroy
articles GET /articles(.:format) articles#index
POST /articles(.:format) articles#create
new_article GET /articles/new(.:format) articles#new
edit_article GET /articles/:id/edit(.:format) articles#edit
article GET /articles/:id(.:format) articles#show
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
photo_comments GET /photos/:photo_id/comments(.:format) comments#index
POST /photos/:photo_id/comments(.:format) comments#create
new_photo_comment GET /photos/:photo_id/comments/new(.:format) comments#new
edit_photo_comment GET /photos/:photo_id/comments/:id/edit(.:format) comments#edit
photo_comment GET /photos/:photo_id/comments/:id(.:format) comments#show
PUT /photos/:photo_id/comments/:id(.:format) comments#update
DELETE /photos/:photo_id/comments/:id(.:format) comments#destroy
photos GET /photos(.:format) photos#index
POST /photos(.:format) photos#create
new_photo GET /photos/new(.:format) photos#new
edit_photo GET /photos/:id/edit(.:format) photos#edit
photo GET /photos/:id(.:format) photos#show
PUT /photos/:id(.:format) photos#update
DELETE /photos/:id(.:format) photos#destroy
event_comments GET /events/:event_id/comments(.:format) comments#index
POST /events/:event_id/comments(.:format) comments#create
new_event_comment GET /events/:event_id/comments/new(.:format) comments#new
edit_event_comment GET /events/:event_id/comments/:id/edit(.:format) comments#edit
event_comment GET /events/:event_id/comments/:id(.:format) comments#show
PUT /events/:event_id/comments/:id(.:format) comments#update
DELETE /events/:event_id/comments/:id(.:format) comments#destroy
events GET /events(.:format) events#index
POST /events(.:format) events#create
new_event GET /events/new(.:format) events#new
edit_event GET /events/:id/edit(.:format) events#edit
event GET /events/:id(.:format) events#show
PUT /events/:id(.:format) events#update
DELETE /events/:id(.:format) events#destroy
comments GET /comments(.:format) comments#index
POST /comments(.:format) comments#create
new_comment GET /comments/new(.:format) comments#new
edit_comment GET /comments/:id/edit(.:format) comments#edit
comment GET /comments/:id(.:format) comments#show
PUT /comments/:id(.:format) comments#update
DELETE /comments/:id(.:format) comments#destroy
root / articles#index
Like so....? This assumes your routes are nested for :Edit, and :update actions under the "commentable" routes.
def edit
#comment = #commentable.comments.find(params[:id])
end
def create
#comment = #commentable.comments.find(params[:id])
if #comment.update_attributes(params[:comment])
redirect_to #commentable, notice: "Comment updated."
else
render :edit
end
end
Your edit should look like this:
<%= link_to 'Edit', [:edit, #comment.commentable, #comment] %>
However... you will want to have some kind of authentication and/or authorization.
I don't have a lot of time to look this over right now, but in response to your tweet I'm posting the code I was using in my test app that I got to work. I'm using HAML here.
When calling for an edit, or delete link in my view I used this partial:
- #category.photos.each do |photo|
= image_tag photo.image_url(:thumb)
%figcaption
= link_to "Change", [:edit, #category, photo]
= link_to "Delete", [#category, photo], :method => :delete
= link_to "New photo", [:new, #category, :photo]
My photos controller:
class PhotosController < ApplicationController
def create
#category = Category.find(params[:category_id])
#photo = #category.photos.create!(params[:photo])
redirect_to #category, :notice => "Photo created."
end
def edit
#category = Category.find(params[:category_id])
#photos = #category.photos
#photo = #photos.find(params[:id])
end
def update
#category = Category.find(params[:category_id])
#photo = #category.photos.find(params[:id])
respond_to do |format|
if #photo.update_attributes(params[:photo])
format.html { redirect_to #category, notice: "<i class=icon-ok /> #{#category.name} was successfully updated."}
format.js
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
def new
#category = Category.find(params[:category_id])
#photo = #category.photos.new
end
def destroy
#category = Category.find(params[:category_id])
#photos = #category.photos
#photo = #photos.find(params[:id])
#photo.destroy
redirect_to #category, :notice => "Photo deleted."
end
end
In my photo model I have:
class Photo
include Mongoid::Document
embedded_in :category, :inverse_of => :photos
field :image
attr_accessible :image
# Set uploader
mount_uploader :image, ImageUploader
end
In the category model:
class Category
# Includes to set up the model
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Ancestry
include Mongoid::Versioning
include Mongoid::Paranoia
include Mongoid::Slug
include Mongoid::History::Trackable
# tell it that it can go nest itself
has_ancestry
embeds_many :photos
# Accept nested attributes
accepts_nested_attributes_for :photos, :autosave => true
# tell history how it can track things
track_history :on => [:name, :description], # track these fields
#:modifier_field => :modifier, # adds "referenced_in :modifier" to track who made the change, default is :modifier
:version_field => :version, # adds "field :version, :type => Integer" to track current version, default is :version
:track_create => false, # track document creation, default is false
:track_update => true, # track document updates, default is true
:track_destroy => false # track document destruction, default is false
# Keep at most 5 versions of a record
max_versions 5
# Add the models fields here
field :name, type: String
field :ancestry, type: String
field :description, type: String
# Set which field the url slug should use
slug :name
# Make sure these attributes can be accessed
attr_accessible :ancestry, :name, :parent_id, :description
# Make name fields capitalized on save
def name=(t)
write_attribute(:name, t.to_s.split(' ').map {|w| w.capitalize}.join(' '))
end
# Create some scopes
scope :except, lambda{ |category| where("id <> ?", category.id)}
end
Notes:
I just pasted a bunch of my code, cause I didn't have too much time to parse it down to answer specifically.
Hopefully the way I've written some of my code can help you.
Keep in mind that I'm using:
Mongoid
Rails 3
Cheers,
-Brandon
This is the destroy action for polymorphic association, I am sure you can figure out the Edit :)
VIEW
<%= link_to content_tag(:i, "", class: "icon-trash icons"), [#commentable, comment], method: :delete,
data: { confirm: "Are you sure?" },
title: "Delete" %>
CONTROLLER
def destroy
#comment = Comment.find(params[:id])
#commentable = #comment.commentable
if #comment.destroy
flash[:success] = "Comment Destroyed!"
redirect_to :back
end
end

Ruby on Rails: Routing error

I am having trouble deleting and showing user records.
Here is my routes.rb
FinalApp::Application.routes.draw do
resources :users
devise_for :users, :controllers => { :registrations => 'admin' }
resources :projects
match "search" => "projects#search", :as => :search
root :to => 'projects#index'
end
Here is my admin controller:
class AdminController < ApplicationController
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #users }
end
end
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
#user_user_id = params[:id]
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
Here is my view:
<%= stylesheet_link_tag "admin" %>
<body>
<div id ="title1">Admin</div>
<div class ="menu"></div>
<div id ="section3">
<table id = "mytable">
<table border = "1">
<tr>
<th>Username </th>
<th>Email</th>
<th>First Name</th>
<th>Last Name</th>
<th>Admin?</th>
<th></th>
<th></th>
<th></th>
</tr>
<%= link_to "New User", admin_new_path %><br />
<% #users.each do |t| %>
<tr>
<td><%= t.username %></td>
<td><%= t.email %></td>
<td><%= t.firstname %></td>
<td><%= t.lastname %></td>
<td><%= t.admin %></td>
<td><%= link_to 'Show', t %></td>
<td> <%= button_to "Delete", t, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table></br>
</body>
</html>
I can display the User database, but when I go to delete a record. I get this error No route matches [DELETE] "/users/11". I am new to rails so please remember this when trying to help. Thanks in advance.
Edit: here are my routes =>
admin_index GET /admin(.:format) admin#index
POST /admin(.:format) admin#create
new_admin GET /admin/new(.:format) admin#new
edit_admin GET /admin/:id/edit(.:format) admin#edit
admin GET /admin/:id(.:format) admin#show
PUT /admin/:id(.:format) admin#update
DELETE /admin/:id(.:format) admin#destroy
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) admin#cancel
user_registration POST /users(.:format) admin#create
new_user_registration GET /users/sign_up(.:format) admin#new
edit_user_registration GET /users/edit(.:format) admin#edit
PUT /users(.:format) admin#update
DELETE /users(.:format) admin#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
PUT /projects/:id(.:format) projects#update
DELETE /projects/:id(.:format) projects#destroy
search /search(.:format) projects#search
root / projects#index
EDIT2: This is how my routes.rb file should have looked. Using rake routes I was able to change the paths to fix my problem.
FinalApp::Application.routes.draw do
# website home
root :to => 'projects#index'
# devise sessions (NB does not use admin/users controller)
devise_for :users, :controllers => { :registrations => 'users' }
# normal controllers
resources :users
resources :projects
# custom routes
match "search" => "projects#search", :as => :search
end
You should add resources :users to your routes.rb. In any case, you can always check rake routes in your console to see the available routes.
On a side note, the way you define you admin routes are not completely correct. Not everything is a get. For example, creating an admin would be a post. The easiest way is just to use something like resources :admins.
You have ended up with two routes leading to admin#destroy:
DELETE /users(.:format) admin#destroy
DELETE /admin/:id(.:format) admin#destroy
and yet you have no route which matches /users/xx, just a route which matches DELETE /users with an optional format bit. You have a route which matches /admin/11 so if you tried that it would work, however I would try to simplify things a bit.
Do you actually need to specify a controller on the devise resources? What exactly do you want to override there, as you have ended up with a load of routes (like cancel) which lead nowhere and some which clash...
Try a simpler routes definition (NB this requires renaming your AdminController UsersController instead, I would follow this convention as it will make your life easier, and match your other urls, so you end up with users/1 etc, not admin/1)
FinalApp::Application.routes.draw do
# website home
root :to => 'projects#index'
# devise sessions (NB does not use admin/users controller)
devise_for :users
# normal controllers
resources :users
resources :projects
# custom routes
match "search" => "projects#search", :as => :search
end
Then do rake routes to make sure you understand where the routes are pointing. You need a route which says (NB the :id bit):
DELETE /users/:id(.:format) users#destroy
or if you prefer an admin controller (and are willing to sort out the custom routes)
DELETE /admin/:id(.:format) admin#destroy
Perhaps before diving into this though you could read through the rails routing guide as it might clear a few things up for you:
http://guides.rubyonrails.org/routing.html
This appears to be a pretty standard use of Devise with your only notable difference being the name of your Controller. Therefore, the only thing you should need for devise routing is:
devise_for :users, :controllers => { :registrations => 'admin' }
Also, delete all of your "get 'admin/*'" entries. Not every HTTP method is a GET when you're working in a REST environment. Here is one article that discusses REST methods.

Resources