I'm trying to hook up a link that will take users from a lesson show page (that lists a bunch of words) to a form to edit one of the listed words. I have a teacher namespace, such that teachers have many lessons and lessons have many words. Before working on a form to edit the word, the lesson show page is breaking when I add the link to what would be the edit form: ActionController::UrlGenerationError in Teacher::Lessons#show, No route matches {:action=>"edit", :controller=>"teacher/words", :id=>nil, :lesson_id=>#<Word id: 19, term: "la casa", reference: "house", lesson_id: 6, created_at: "2016-06-05 23:19:19", updated_at: "2016-06-05 23:19:19", image: "house.jpeg", sound: "test.mp3">} missing required keys: [:id]
What am I missing in regards to setting the edit_teacher_lesson_word link?
Rails.application.routes.draw do
devise_for :users
root 'static_pages#index'
resources :lessons, only: [:index, :show]
resources :words, only: [:show]
namespace :teacher do
resources :lessons, only: [:show, :new, :edit, :create, :update] do
resources :words, only: [:new, :edit, :create, :update]
end
end
end
teacher/words_controller:
class Teacher::WordsController < ApplicationController
before_action :authenticate_user!
before_action :require_authorized_for_current_lesson
def new
#word = Word.new
end
def edit
#word = Word.find(params[:id])
end
def create
#word = current_lesson.words.create(word_params)
if #word.valid?
redirect_to teacher_lesson_path(current_lesson)
else
render :new, status: :unprocessable_entity
end
end
private
def require_authorized_for_current_lesson
if current_lesson.user != current_user
render text: 'Unauthorized', status: :unauthorized
end
end
helper_method :current_lesson
def current_lesson
#current_lesson ||= Lesson.find(params[:lesson_id])
end
def word_params
params.require(:word).permit(:term, :reference, :image, :sound)
end
end
teacher/lessons_controller:
class Teacher::LessonsController < ApplicationController
before_action :authenticate_user!
before_action :require_authorized_for_current_lesson, only: [:show, :edit, :update]
def show
#lesson = Lesson.find(params[:id])
end
def new
#lesson = Lesson.new
end
def edit
#lesson = Lesson.find(params[:id])
end
def create
#lesson = current_user.lessons.create(lesson_params)
if #lesson.valid?
redirect_to teacher_lesson_path(#lesson)
else
render :new, status: :unprocessable_entity
end
end
def update
current_lesson.update_attributes(lesson_params)
redirect_to teacher_lesson_path(current_lesson)
end
private
def require_authorized_for_current_lesson
if current_lesson.user != current_user
render text: "Unauthorized", status: :unauthorized
end
end
def current_lesson
#current_lesson ||= Lesson.find(params[:id])
end
def lesson_params
params.require(:lesson).permit(:title, :description, :subject, :difficulty)
end
end
teacher/lessons/show:
<div class ="booyah-box col-xs-10 col-xs-offset-1">
<br>
<p class="text-center"><%= #lesson.description %></p>
<br>
<div class="text-center">
<%= link_to 'Edit Lesson', edit_teacher_lesson_path(#lesson), class: 'btn btn-primary' %>
<%= link_to 'Student View', lesson_path(#lesson), class: 'btn btn-warning' %>
<%= link_to 'My Lessons', '#', class: 'btn btn-success' %>
<%= link_to 'All Lessons', lessons_path, class: 'btn btn-info' %>
</div>
<hr>
<h3>Vocabulary in This Lesson</h3>
<%= link_to 'Add word', new_teacher_lesson_word_path(#lesson), class: 'btn btn-primary btn-lg pull-right' %>
<ul>
<% #lesson.words.each do |word| %>
<li>
<b><%= word.term %></b> means <i><%= word.reference %></i>
<%= link_to 'Edit', edit_teacher_lesson_word_path(word), class: 'btn btn-primary' %>
</li>
<% end %>
</ul>
</div>
rake routes:
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
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
root GET / static_pages#index
lessons GET /lessons(.:format) lessons#index
lesson GET /lessons/:id(.:format) lessons#show
word GET /words/:id(.:format) words#show
teacher_lesson_words POST /teacher/lessons/:lesson_id/words(.:format) teacher/words#create
new_teacher_lesson_word GET /teacher/lessons/:lesson_id/words/new(.:format) teacher/words#new
edit_teacher_lesson_word GET /teacher/lessons/:lesson_id/words/:id/edit(.:format) teacher/words#edit
teacher_lesson_word PATCH /teacher/lessons/:lesson_id/words/:id(.:format) teacher/words#update
PUT /teacher/lessons/:lesson_id/words/:id(.:format) teacher/words#update
teacher_lessons POST /teacher/lessons(.:format) teacher/lessons#create
new_teacher_lesson GET /teacher/lessons/new(.:format) teacher/lessons#new
edit_teacher_lesson GET /teacher/lessons/:id/edit(.:format) teacher/lessons#edit
teacher_lesson GET /teacher/lessons/:id(.:format) teacher/lessons#show
PATCH /teacher/lessons/:id(.:format) teacher/lessons#update
PUT /teacher/lessons/:id(.:format) teacher/lessons#update
looks like you're passing a Word where it's expecting a Lesson. see this part of the error message: :lesson_id=>#<Word id: 19,
I'm guessing, but probably this is the wrong line of code:
edit_teacher_lesson_word_path(word)
your route file says this about that route:
edit_teacher_lesson_word GET /teacher/lessons/:lesson_id/words/:id/edit(.:format)
the : indicates what things you need to pass in order to create a valid route... and here you need both :lesson_id as well as :id and you are only passing one of those (and it's getting confused about which one).
Usually you'd instantiate this route with both lesson and word eg:
edit_teacher_lesson_word_path(#lesson, word)
Try that (or variations on it) to get it to work.
Related
I'm using Acts_as_follower in a wishlist app I'm working on. I think it should be working, but the button to actually follow another user is not. The follow button is in my user index view, and I can see it there, but it doesn't respond to being clicked. Any help would be appreciated. Here's my code:
index.html.erb
<div class="container">
<% #users.each do |u| %>
<div class="col-sm-8 col-lg-4">
<div id="gifts">
<div class="box panel panel-default">
<h2><%= link_to u.name, u %></h2>
<p>
<table align="center" margin="5">
<tr>
<th style="padding-right: 10px"><%= button_to "View Wishlist", u, method: :get, class: "btn btn-primary" %></th>
<th>
<% if current_user.following?(u) %>
<%= form_tag user_unfollow_path(user_id: u.id), method: :delete, remote: true do %>
<%= button_tag 'unfollow', class: 'btn btn-primary' %>
<% end %>
<% else %>
<%= form_tag user_follow_path(user_id: u.id), method: :post, remote: true do %>
<%= button_tag 'follow', class: 'btn btn-success' %>
<% end %>
<% end %>
</th>
</tr>
</table>
<p>
</div>
</div>
</div>
<% end %>
</div>
followers_controller.rb
class FollowersController < ApplicationController
before_action :authenticate_user!
respond_to :js
def create
#user = User.find(params[:user_id])
current_user.follow(#user)
end
def destroy
#user = User.find(params[:user_id])
current_user.stop_following(#user)
end
end
users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#gifts = #user.gifts
end
def index
#users = User.all
if params[:search]
#users = User.search(params[:search]).order("created_at DESC")
else
#users = User.all.order("created_at DESC")
end
end
def create
#user = User.find(params[:user_id])
current_user.follow(#user)
end
def destroy
#user = User.find(params[:user_id])
current_user.stop_following(#user)
end
private
def get_gifts
#gifts = Gift.find(params[:id])
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users
resources :users, only: [:index] do
post :follow, :to => 'followers#create'
delete :unfollow, :to => 'followers#destroy'
end
resources :gifts
resources :wishlists
get 'wishlists/index'
get '/wishlists', :to => 'wishlists#index'
get '/users/:id', :to => 'users#show', :as => :user
get '/users', :to => 'users#index'
root "gifts#index"
end
user.rb (model)
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
acts_as_follower
acts_as_followable
has_many :gifts
belongs_to :wishlist
def self.search(search)
where("name ILIKE ?", "%#{search}%")
end
end
routes:
C:\Sites\gladlygift>rake routes
Prefix Verb URI Pattern Controller#A
tion
new_user_session GET /users/sign_in(.:format) devise/sessi
ns#new
user_session POST /users/sign_in(.:format) devise/sessi
ns#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessi
ns#destroy
user_password POST /users/password(.:format) devise/passw
rds#create
new_user_password GET /users/password/new(.:format) devise/passw
rds#new
edit_user_password GET /users/password/edit(.:format) devise/passw
rds#edit
PATCH /users/password(.:format) devise/passw
rds#update
PUT /users/password(.:format) devise/passw
rds#update
cancel_user_registration GET /users/cancel(.:format) devise/regis
rations#cancel
user_registration POST /users(.:format) devise/regis
rations#create
new_user_registration GET /users/sign_up(.:format) devise/regis
rations#new
edit_user_registration GET /users/edit(.:format) devise/regis
rations#edit
PATCH /users(.:format) devise/regis
rations#update
PUT /users(.:format) devise/regis
rations#update
DELETE /users(.:format) devise/regis
rations#destroy
user_follow POST /users/:user_id/follow(.:format) followers#cr
ate
user_unfollow DELETE /users/:user_id/unfollow(.:format) followers#de
troy
users GET /users(.:format) users#index
gifts GET /gifts(.:format) gifts#index
POST /gifts(.:format) gifts#create
new_gift GET /gifts/new(.:format) gifts#new
edit_gift GET /gifts/:id/edit(.:format) gifts#edit
gift GET /gifts/:id(.:format) gifts#show
PATCH /gifts/:id(.:format) gifts#update
PUT /gifts/:id(.:format) gifts#update
DELETE /gifts/:id(.:format) gifts#destro
wishlists GET /wishlists(.:format) wishlists#in
ex
POST /wishlists(.:format) wishlists#cr
ate
new_wishlist GET /wishlists/new(.:format) wishlists#ne
edit_wishlist GET /wishlists/:id/edit(.:format) wishlists#ed
t
wishlist GET /wishlists/:id(.:format) wishlists#sh
w
PATCH /wishlists/:id(.:format) wishlists#up
ate
PUT /wishlists/:id(.:format) wishlists#up
ate
DELETE /wishlists/:id(.:format) wishlists#de
troy
wishlists_index GET /wishlists/index(.:format) wishlists#in
ex
GET /wishlists(.:format) wishlists#in
ex
user GET /users/:id(.:format) users#show
GET /users(.:format) users#index
root GET / gifts#index
I have a view which lists all my comparisons
index.html.erb
<% #comparisons.each do |comparison| %>
<div class="col-xs-6 col-sm-4 col-md3">
<p><%= comparison.title %></p>
<p><%= comparison.id %></p>
<p><%= comparison.description %></p>
</div>
<% end %>
Up to now, all is going well : title, description and id are displayed for each comparison.
I tried to add a Show link :
<% #comparisons.each do |comparison| %>
<div class="col-xs-6 col-sm-4 col-md3">
<p><%= comparison.title %></p>
<p><%= comparison.id %></p>
<p><%= comparison.description %></p>
<p><%= link_to 'Show', comparison_path(comparison) %></p>
</div>
<% end %>
But now, when I load index.html.erb I have this error :
No route matches {:action=>"show", :controller=>"comparisons", :format=>nil, :id=>nil, :locale=>#<Comparison id: 1, title: "coucou", description: "", created_at: "2015-07-04 10:33:47", updated_at: "2015-07-04 10:33:47", user_id: 1>} missing required keys: [:id]
I don't understand why...
comparisons_controller.rb
class ComparisonsController < ApplicationController
before_action :set_comparison, only: [ :show ]
skip_before_action :authenticate_user!, only: [ :index, :show ]
def index
#comparisons = policy_scope(Comparison)
end
def show
end
def new
#comparison = current_user.comparisons.new
authorize #comparison
end
def create
#comparison = current_user.comparisons.new(comparison_params)
authorize #comparison
if #comparison.save
# redirect_to comparison_path(#comparison)
# redirect_to #comparison
render :show
else
render :new
end
end
private
def set_comparison
#comparison = Comparison.find(params[:id])
authorize #comparison
end
def comparison_params
params.require(:comparison).permit(:title, :description, :user_id)
end
end
By the way, as you can see, in create action, I have not been able to use a redirect_to. But render :show works : the show.html.erb view is loaded.
Any risks to use render rather redirect_to ?
My routes
Prefix Verb URI Pattern Controller#Action
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
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
page GET (/:locale)/pages/:id high_voltage/pages#show {:locale=>/fr/}
comparisons GET (/:locale)/comparisons(.:format) comparisons#index {:locale=>/fr/}
POST (/:locale)/comparisons(.:format) comparisons#create {:locale=>/fr/}
new_comparison GET (/:locale)/comparisons/new(.:format) comparisons#new {:locale=>/fr/}
comparison GET (/:locale)/comparisons/:id(.:format) comparisons#show {:locale=>/fr/}
home GET /home(.:format) redirect(301, /)
root GET / high_voltage/pages#show {:id=>"home"}
routes.rb
Rails.application.routes.draw do
devise_for :users
scope '(:locale)', locale: /fr/ do
get 'pages/:id' => 'high_voltage/pages#show', :as => :page, :format => false
resources :comparisons, only: [ :index, :show, :new, :create ]
end
end
Thanks in advance for your help.
Seeing from your routes files, it looks to me that to construct a route, you need two parameters - locale and id. Since you are using comparison_path(comparison), rails is assuming that the first parameter you are passing refers to locale.
To construct a correct route, use a cleaner way to construct a route - like this:
comparison_path(locale: 'en', id: comparison.id)
Previous answers made me realize I had a routing issue with i18n : locale parameter was not considered in urls building.
In application_controller.rb I still have
before_action :set_locale
private
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
I add this second method which automatically add the locale parameter to urls
def default_url_options
{ locale: I18n.locale == I18n.default_locale ? nil : I18n.locale }
end
Now, it works fine.
Thanks for your help.
Alternatively you can use like this:
<% #comparisons.each do |comparison| %>
<div class="col-xs-6 col-sm-4 col-md3">
<p><%= comparison.title %></p>
<p><%= comparison.id %></p>
<p><%= comparison.description %></p>
<p><%= link_to 'Show', comparison %></p>
</div>
<% end %>
It seems to me using :shallow_path would be the answer. From the documentation.
The :path, :as, :module, :shallow_path and :shallow_prefix options all default to the name of the namespace.
I think this will remove (/:locale) from the raked routes
scope '(:locale)', locale: /fr/, :shallow_path => '(:locale)' do
get 'pages/:id' => 'high_voltage/pages#show', :as => :page, :format => false
resources :comparisons, only: [ :index, :show, :new, :create ]
end
I'm trying to associate "Notes" with "Account one the same page (show.html.erb) once the note is created. However, once I create the note for the associated account I get undefined local variable or method `accounts' for NotesController:0x0000000545e1d8"
Notes were being created fine up until the point of association.
with #account = accounts.find(params[:account_id]) highlighted on like 65.
**Parameters:** (on debug page)
{"utf8"=>"✓",
"authenticity_token"=>"gm6gJ3mYDDVmDHnsB2JqhOtOY1Lc9n3P7Yuq9gpqdo4=",
"note"=>{"comment"=>"1221211212"},
"commit"=>"Create Note",
"account_id"=>"1"}
Running Rails 4.1.8 and
ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-linux]
note_colltroler.rb
class NotesController < ApplicationController
before_action :set_note, only: [:edit, :update, :destroy]
before_action :set_account
before_action :authenticate_user!
before_action :check_user, only: [:edit, :update, :destroy]
# GET /notes/new
def new
#note = note.new
end
# GET /notes/1/edit
def edit
end
# POST /notes
# POST /notes.json
def create
#note = note.new(note_params)
#note.user_id = current_user.id
#note.account_id = #account.id
respond_to do |format|
if #note.save
format.html { redirect_to #account, notice: 'note was successfully created.' }
format.json { render :show, status: :created, location: #note }
else
format.html { render :new }
format.json { render json: #note.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /notes/1
# PATCH/PUT /notes/1.json
def update
respond_to do |format|
if #note.update(note_params)
format.html { redirect_to account_path(#account), notice: 'note was successfully updated.' }
format.json { render :show, status: :ok, location: #note }
else
format.html { render :edit }
format.json { render json: #note.errors, status: :unprocessable_entity }
end
end
end
# DELETE /notes/1
# DELETE /notes/1.json
def destroy
#note.destroy
respond_to do |format|
format.html { redirect_to account_path(#account), notice: 'note was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_note
#note = note.find(params[:id])
end
def set_account
#account = accounts.find(params[:account_id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def note_params
params.require(:note).permit(:comment)
end
end
note.rb
class Note < ActiveRecord::Base
belongs_to :user
belongs_to :account
end
account.rb
class Account < ActiveRecord::Base
belongs_to :program
has_many :notes
end
Rake Routes
Prefix Verb URI Pattern Controller#Action
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
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
account_notes POST /accounts/:account_id/notes(.:format) notes#create
new_account_note GET /accounts/:account_id/notes/new(.:format) notes#new
edit_account_note GET /accounts/:account_id/notes/:id/edit(.:format) notes#edit
account_note PATCH /accounts/:account_id/notes/:id(.:format) notes#update
PUT /accounts/:account_id/notes/:id(.:format) notes#update
DELETE /accounts/:account_id/notes/:id(.:format) notes#destroy
accounts GET /accounts(.:format) accounts#index
POST /accounts(.:format) accounts#create
new_account GET /accounts/new(.:format) accounts#new
edit_account GET /accounts/:id/edit(.:format) accounts#edit
account GET /accounts/:id(.:format) accounts#show
PATCH /accounts/:id(.:format) accounts#update
PUT /accounts/:id(.:format) accounts#update
DELETE /accounts/:id(.:format) accounts#destroy
programs GET /programs(.:format) programs#index
POST /programs(.:format) programs#create
new_program GET /programs/new(.:format) programs#new
edit_program GET /programs/:id/edit(.:format) programs#edit
program GET /programs/:id(.:format) programs#show
PATCH /programs/:id(.:format) programs#update
PUT /programs/:id(.:format) programs#update
DELETE /programs/:id(.:format) programs#destroy
pages_index GET /pages/index(.:format) pages#index
root GET / pages#index
For Notes show.html.erb
<div class="row">
<div class="col-md-3">
<p>
<strong>First name:</strong>
<%= #account.first_name %>
</p>
<p>
<strong>Last name:</strong>
<%= #account.last_name %>
</p>
<p>
<strong>Program:</strong>
<%= #account.program.program %>
</p>
<p>
<strong>Address:</strong>
<%= #account.address %>
</p>
<p>
<strong>Phone:</strong>
<%= #account.phone %>
</p>
<p>
<strong>Created:</strong>
<%= #account.created_at %>
</p>
<%= link_to "Write a Note", new_account_note_path(#account), class: "btn btn-primary" %>
</div>
<div class="col-md-9">
<% #notes.each do |note| %>
<p><%= note.comment %></p>
<% end %>
<%= link_to 'Edit', edit_account_path(#account), class: "btn btn-link" %> |
<%= link_to 'Back', account_path, class: "btn btn-link" %>
</div>
</div>
Instead of
#account = accounts.find(params[:account_id])
try
#account = Account.find(params[:account_id])
Learn more about .find and other query methods here. Most of them are called on an
Side Note:
As #apneadiving pointed out, you generally want to use some sort of authorisation. I don't think you want users to be able to edit accounts of other users. With your current implementation this is possible by simply experimenting in with the account and note ids in the url (e.g. by getting /accounts/1/notes/2/edit any user can edit note 2 of account 1).
Consider scoping records for the current user. One approach is described here.
in
def set_account
#account = accounts.find(params[:account_id])
end
accounts is not defined
I'm learning Rails. I've got an app that has "Ideas", which have "Comments"
I've created the comments using this guide (https://gorails.com/episodes/comments-with-polymorphic-associations)
I am using the 'Ancestry' gem to attempt make them nested using this guide on railscasts (http://railscasts.com/episodes/262-trees-with-ancestry)
Anyways I'm getting this error "ActionController::RoutingError (uninitialized constant Comments):"
This is where I'm getting the error – when I hit the "Reply" link
<h3> Comments </h3>
<% #idea.comments.each do |comment| %>
<div>
<%= comment.body %>
<div class="actions">
<%= link_to "Reply", new_comment_path(:parent_id => comment) %>
</div>
</div>
<% end %>
The above is being rendered on the "Ideas/show.html" page
<p id="notice"><%= notice %></p>
<p>
<strong>Description:</strong>
<%= #idea.description %>
</p>
<%= render partial: "comments/comments", locals: {commentable: #idea} %>
<%= render partial: "comments/form", locals: {commentable: #idea} %>
<% if #idea.user == current_user %>
<%= link_to 'Edit', edit_idea_path(#idea) %>
<% end %>
<%= link_to 'Back', ideas_path %>
I want to send them here to "Comments/new" which is the same as my form page
<%= form_for [commentable, Comment.new] do |f| %>
<div class="form-group">
<%= f.hidden_field :parent_id %>
<%= f.text_area :body, class: "form-control", placeholder: "Add a comment here" %>
</div>
<%= f.submit class: "btn btn-primary" %>
<% end %>
Routes.rb
Rails.application.routes.draw do
resources :ideas do
resources :comments, module: :ideas
end
devise_for :users
root 'ideas#index'
get "about" => "pages#about"
get "new_comment" => "comments/new"
end
Comments_controller.rb
class CommentsController < ApplicationController
before_action :authenticate_user!
def new
#comment = Comment.new(:parent_id => params[:parent_id])
end
def create
#comment = #commentable.comments.new comment_params
#comment.user = current_user
#comment.save
redirect_to #commentable, notice: "Your comment was posted"
end
private
def comment_params
params.require(:comment).permit(:body)
end
end
Ideas_controller.rb
class IdeasController < ApplicationController
before_action :set_idea, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
before_action :correct_user, only: [:edit, :update, :destroy]
respond_to :html
def index
#ideas = Idea.all
end
def show
end
def new
#idea = Idea.new
#idea.comments.build
respond_with(#idea)
end
def edit
end
def create
#idea = current_user.ideas.build(idea_params)
if #idea.save
redirect_to #idea, notice: "Idea was successfully created."
else
render :action => 'new'
end
end
def update
if #idea.update(idea_params)
redirect_to #idea, notice: "Your idea has been updated"
else
render action: 'edit'
end
end
def destroy
#idea.destroy
redirect_to ideas_url
end
private
def set_idea
#idea = Idea.find(params[:id])
end
def correct_user
#idea = current_user.ideas.find_by(id: params[:id])
redirect_to ideas_path, notice: "You can't edit this" if #idea.nil?
end
def idea_params
params.require(:idea).permit(:description)
end
end
Any help would be much appreciated, thank you.
EDIT _ Added my routes
idea_comments GET /ideas/:idea_id/comments(.:format) ideas/comments#index
POST /ideas/:idea_id/comments(.:format) ideas/comments#create
new_idea_comment GET /ideas/:idea_id/comments/new(.:format) ideas/comments#new
edit_idea_comment GET /ideas/:idea_id/comments/:id/edit(.:format) ideas/comments#edit
idea_comment GET /ideas/:idea_id/comments/:id(.:format) ideas/comments#show
PATCH /ideas/:idea_id/comments/:id(.:format) ideas/comments#update
PUT /ideas/:idea_id/comments/:id(.:format) ideas/comments#update
DELETE /ideas/:idea_id/comments/:id(.:format) ideas/comments#destroy
ideas GET /ideas(.:format) ideas#index
POST /ideas(.:format) ideas#create
new_idea GET /ideas/new(.:format) ideas#new
edit_idea GET /ideas/:id/edit(.:format) ideas#edit
idea GET /ideas/:id(.:format) ideas#show
PATCH /ideas/:id(.:format) ideas#update
PUT /ideas/:id(.:format) ideas#update
DELETE /ideas/:id(.:format) ideas#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
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
root GET / ideas#index
about GET /about(.:format) pages#about
new_comment GET /new_comment(.:format) comments/new#new_comment
I am wrapping my head around the Rails framework and routes. I am building a site where users can post Rails articles and tips and I've already added a ton of functionality to my site but I am having an issue with nested resources. I want my users to create post. I also want the same user and other users to leave comments on the post. Now, the tricky part is that I need a way for them to edit their own comment. So once they go to a post>comment>edit, I am receiving a No route matches [GET] "/posts/48/comments/edit" and this is from the Post show template. For tht particular post, I can tell by the error that it cannot find the id of that comment to edit it. I am sure that this is nested resources issue but I cant wrap my head on it. Looking at my code, everything seems in tact to me. Any ideas? Thanks in advance for any insight.
routes.rb file
PostitTemplate::Application.routes.draw do
root to: 'posts#index'
get '/register', to: 'users#new'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
get '/logout', to: 'sessions#destroy'
resources :users, only: [:create, :edit, :update]
resources :posts, except: [:destroy] do
member do
post 'vote'
end
resources :comments, only: [:create, :edit, :update] do
member do
post 'vote'
end
end
end
resources :categories, only: [:new, :create]
end
comments_controller
class CommentsController < ApplicationController
before_action :require_user
def create
#post = Post.find(params[:post_id])
#comment = Comment.new(params.require(:comment).permit(:body))
#comment.post = #post
#comment.creator = current_user
if #comment.save
flash[:notice] = "Your comment was created!"
redirect_to post_path(#post)
else
render 'posts/show'
end
end
def edit
#comment = Comment.find(params[:id])
#post = Post.find(params[:post_id])
end
def update
#comment = Comment.find(params[:id])
if #comment.update(comment_params)
flash[:notice] = "You updated your comment!"
redirect_to post_path
else
render :edit
end
end
private
def comment_params
params.require(:comment).permit(:body)
end
def set_comment
#comment = Comment.find(params[:id])
end
end
posts_controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :vote]
before_action :require_user, only: [:new, :create, :edit, :update, :vote]
before_action :require_creator, only:[:edit, :update]
def index
#posts = Post.all.page(params[:page]).per_page(10)
end
def show
#comment = Comment.new
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.creator = current_user
if #post.save
flash[:notice] = "You created a post!"
redirect_to posts_path
else
render :new
end
end
def edit
end
def update
if #post.update(post_params)
flash[:notice] = "You updated the post!"
redirect_to post_path(#post)
else
render :edit
end
end
def vote
Vote.create(voteable: #post, creator: current_user, vote: params[:vote])
respond_to do |format|
format.js { render :vote } # Renders views/posts/vote.js.erb
end
end
private
def post_params
params.require(:post).permit(:url, :title, :description)
end
def set_post
#post = Post.find(params[:id])
end
def require_creator
access_denied if #post.creator != current_user
end
end
show.html.erb(This is the show post template and on line 33, I want to link to the comments controller edit action)
<div class="page-header">
<h2>
<%= #post.title %>
<small>
posted by <%= link_to #post.creator.username %> about <%= time_ago_in_words(#post.created_at) + ' ago' %>
| <%= link_to 'check out the link', fix_url(#post.url) %> |
<%= link_to 'edit', edit_post_path(#post) %>
</small>
</h2>
</div>
<h3><%= #post.description %></h3>
<%= render 'shared_partials/errors', errors_obj: #comment %>
<%= form_for [#post, #comment] do |f| %>
<%= f.text_area :body, :class=> "input", :placeholder=> "Comment goes here", :rows => "6" %>
</br>
<div class="button">
<%= f.submit "Create a comment", class: 'btn btn-primary' %>
</div>
<% end %>
<div class="page-header">
<h4>All Comments</h4>
</div>
<% #post.comments.each do |comment| %>
<div class="comments">
<h5><%= comment.body %></h5>
<li>
<small class="muted">
posted by <%= link_to comment.creator.username %> about <%= time_ago_in_words(comment.created_at) + ' ago' %>
<% if logged_in? && (comment.creator == current_user) %> |
<%= link_to 'edit', edit_post_comment_path(#post, #comment) %> |
<i class="icon-user icon"></i>
<% end %>
</small>
</li>
</div>
<% end %>
Finally my rake routes
root_path GET / posts#index
register_path GET /register(.:format) users#new
login_path GET /login(.:format) sessions#new
POST /login(.:format) sessions#create
logout_path GET /logout(.:format) sessions#destroy
users_path POST /users(.:format) users#create
edit_user_path GET /users/:id/edit(.:format) users#edit
user_path PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
vote_post_path POST /posts/:id/vote(.:format) posts#vote
vote_post_comment_path POST /posts/:post_id/comments/:id/vote(.:format) comments#vote
post_comments_path POST /posts/:post_id/comments(.:format) comments#create
edit_post_comment_path GET /posts/:post_id/comments/:id/edit(.:format) comments#edit
post_comment_path PATCH /posts/:post_id/comments/:id(.:format) comments#update
PUT /posts/:post_id/comments/:id(.:format) comments#update
posts_path GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post_path GET /posts/new(.:format) posts#new
edit_post_path GET /posts/:id/edit(.:format) posts#edit
post_path GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
categories_path POST /categories(.:format) categories#create
new_category_path GET /categories/new(.:format) categories#new
Replace
<%= link_to 'edit', edit_post_comment_path(#post, #comment) %>
with
<%= link_to 'edit', edit_post_comment_path(#post, comment) %>
You need to pass the current comment, not the new one.
Also, you don't necessarily have to nest the comment resource.