**ARTICLE CONTROLLER** //controller
class ArticlesController < ApplicationController
def index
#article=Article.all
end
def show
#article=Article.find(params[:id])
#comment = Comment.new
#comment.article_id = #article.id
end
def new
#article=Article.new
end
def create
#article = Article.new(article_params)
#article.save
redirect_to article_path(#article)
end
def destroy
article=Article.find(params[:id])
article.destroy
redirect_to articles_path
end
def edit
#article = Article.find(params[:id])
end
def update
#article = Article.find(params[:id])
#article.update(article_params)
flash.notice = "Article '#{#article.title}' Updated!"
redirect_to article_path(#article)
end
def article_params
params.require(:article).permit(:title, :body)
end
end
**SHOW.HTML.ERB** /view file
<h1><%=#article.title%></h1>
<p><%=#article.body%></p>
<br><hr>
<%= link_to "edit", edit_article_path(#article) %>|
<%= link_to "delete",article_path(#article), method: :delete,data: {confirm: "Really delete the article?"} %>|
<%= link_to "<< Back to Articles List", articles_path %>
<h3>Comments</h3>
<%= render partial: 'articles/comment', collection: #article.comments %>
<%= render partial: 'comments/form' %>
**_FORM.HTML.ERB** //_form view
<h3>Post a Comment</h3>
<%= form_for [ #article, #comment ] do |f| %>
<p>
<%= f.label :author_name %><br/>
<%= f.text_field :author_name %>
</p>
<p>
<%= f.label :body %><br/>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit 'Submit' %>
</p>
<% end %>
rake routes:
Prefix Verb URI Pattern Controller#Action
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
PATCH /articles/:id(.:format) articles#update
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
root GET / articles#index
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
PATCH /comments/:id(.:format) comments#update
PUT /comments/:id(.:format) comments#update
DELETE /comments/:id(.:format) comments#destroy
i get no articles_comments_path!
NoMethodError in Articles#show
Showing /home/manoj/ror/blogger/app/views/comments/_form.html.erb where line #3 raised:
undefined method article_comments_path' for #<#<Class:0x00000005be3d40>:0x000000054cacc0>
app/views/comments/_form.html.erb:3:in_app_views_comments__form_html_erb__3077497298558231225_47236640'
app/views/articles/show.html.erb:11:in `_app_views_articles_show_html_erb__4529829459036724249_48053660'
You are getting this error because you don't have article_comments_path helper method. Change your routes to this:
resources :articles do
resources :comments
end
OR
If you don't want to nest routes then change your form to this:
<%= form_for #comment do |f| %>
// form fields
<% end %>
Also in show action you can dry up your code by using association methods
def show
#article= Article.find(params[:id])
#comment = #article.comments.build
end
Related
I am started learning Ruby. I just followed this guide http://guides.rubyonrails.org/getting_started.html to create blog app. One thing I noticed if we try to submit the form without entering data from url http://localhost:3000/articles/new it showing error message and redirect to http://localhost:3000/articles
I think it should keep same url and show error message.
Not sure how to fix that.
articles_controller.rb
class ArticlesController < ApplicationController
def index
#articles = Article.all
end
def show
#article = Article.find(params[:id])
end
def new
#article = Article.new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
new.html.erb
<%= form_with scope: :article, url: articles_path, local: true do |form| %>
<% if #article.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#article.errors.count, "error") %> prohibited
this article from being saved:
</h2>
<ul>
<% #article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :text %><br>
<%= form.text_area :text %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
<%= link_to 'Back', articles_path %>
routes.rb
Rails.application.routes.draw do
get 'welcome/index'
resources :articles
root 'welcome#index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
rails routes
Prefix Verb URI Pattern Controller#Action
welcome_index GET /welcome/index(.:format) welcome#index
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
PATCH /articles/:id(.:format) articles#update
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
root GET / welcome#index
This is the standard behavior. If you want to change it however to keep the URL, you can modify the new and create actions:
def new
if article_params
create
return
end
#article = Article.new
render 'new'
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
And in routes.rb:
resources :articles
post "articles/new"
#Shannon answer is correct, I'm writing this for your comment on his answer, Try to use model argument, according to this when you gonna use model: #article it will generate everything automatically for you
Hope it helps.
I am a beginner in Rails and I have been trying to solve this issue for hours. I've searched and applied many solutions but none have worked to solve this issue.
The app is a simple blog with articles and comments. I have made them using scaffold in this project and have them nested in routes.rb with associations in the database.
The problem now is that the partial for the comments form is not working to add any comment at all.
The partial form for the comment:
<%= form_with(url: article_comments_path) do |form| %>
<% if comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% comment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :commenter %>
<%= form.text_field :commenter, id: :comment_commenter %>
</div>
<div class="field">
<%= form.label :body %>
<%= form.text_field :body, id: :comment_body %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
Article model:
class Article < ApplicationRecord
has_many :comments
accepts_nested_attributes_for :comments
end
Comment model:
class Comment < ApplicationRecord
belongs_to :article
end
Comments controller:
def create
#article = Article.find(params[:article_id])
#comment = Comment.new(comment_params)
redirect_to article_path(#article)
#article_id = params[:article_id]
#raise params.inspect
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:commenter, :body)
end
The error I got on the form page for the comment after clicking submit:
ActionController::ParameterMissing in CommentsController#create
param is missing or the value is empty: comment Extracted source (around line #437):
#435 value
#436 else
*437 raise ParameterMissing.new(key)
#438 end
#439 end
#440
Extracted source (around line #73):
#71 # Never trust parameters from the scary internet, only allow the white list through.
#72 def comment_params
*73 params.require(:comment).permit(:commenter, :body)
#74 end
#75 end
Extracted source (around line #36):
#34
#35 #article = Article.find(params[:article_id])
*36 #comment = #article.comments.create(comment_params)
#37 redirect_to article_path(#article)
#38
#39 end
routes.rb
Prefix Verb URI Pattern Controller#Action
rails_admin /admin RailsAdmin::Engine
article_comments GET /articles/:article_id/comments(.:format) comments#index
POST /articles/:article_id/comments(.:format) comments#create
new_article_comment GET /articles/:article_id/comments/new(.:format) comments#new
edit_article_comment GET /articles/:article_id/comments/:id/edit(.:format) comments#edit
article_comment GET /articles/:article_id/comments/:id(.:format) comments#show
PATCH /articles/:article_id/comments/:id(.:format) comments#update
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
PATCH /articles/:id(.:format) articles#update
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
The server log for that action
Started POST "/articles/8/comments" for 127.0.0.1 at 2017-09-02 20:18:44 +0300
Processing by CommentsController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"vy35XCR5S4E7rREcavLifxAPqwzPOrl0bVbbWA4nyXgQDWFLxJYu/2YVa/NdnJGBwN7mCW8RjliPUnkGPtPwnQ==", "commenter"=>"asdasd", "body"=>"sdfdfgdf", "commit"=>"Save ", "article_id"=>"8"}
[1m[36mArticle Load (5.2ms)[0m [1m[34mSELECT "articles".* FROM "articles" WHERE "articles"."id" = $1 LIMIT $2[0m [["id", 8], ["LIMIT", 1]]
Completed 400 Bad Request in 35ms (ActiveRecord: 5.2ms)
ActionController::ParameterMissing (param is missing or the value is empty: comment):
app/controllers/comments_controller.rb:71:in `comment_params'
app/controllers/comments_controller.rb:33:in `create'
Important note:
if I remove
params.require(:comment)
the submit will pass & I will be redirected to the right page , the issue though is that it won't save the comment itself.
Please advise as I am feeling lost
Thank you all.
Your form_with isn't set up correctly. You need to build it so that it is associated with a model.
<%= form_with article_comments_path(Comment.new) do |form| %>
... parameters here...
<% end %>
Will work I believe.
Here's a nice article on Medium
EDIT:
This should work if you're in the Articles#Show
def create
#article = Article.find(params[:id])
#comment = #article.comments.create(comment_params)
redirect_to article_path(#article)
end
This will depend on how you've set up routes though.
Hope this helps someone else , only two changes fixed the code:
1- removing the require commment in the comment_params
def comment_params
params**.require(:comment)**.permit(:commenter, :body, :article_id)
end
2- the create action didn't have a save after making the comment
def create
#article = Article.find(params[:article_id])
#comment = Comment.new(comment_params)
if #comment.save
redirect_to article_path(#article)
end
end
Thanks for your help.
I am trying to edit an article and re-save it. I can create a new article and save that. I can even comment on the article and save that. When I go to edit the article it auto populates the form with the text to be edited but when I try to save that it gives me the "No route matches [Patch]"/artices.7" error.
article controller
class ArticlesController < ApplicationController
def index
#articles = Article.all
end
def show
#articles = Article.find(params[:id])
end
def new
#articles = Article.new
end
def edit
#articles = Article.find(params[:id])
end
def create
#articles = Article.new(articles_params)
if #articles.save
redirect_to #articles
else
render 'new'
end
end
def update
#articles = Article.find(params[:id])
if #articles.update(articles_params)
redirect_to #articles
else
render 'edit'
end
end
def destroy
#articles = Article.find(params[:id])
#articles.destroy
redirect_to articles_path
end
private
def articles_params
params.require(:articles).permit(:title, :text)
end
end
comment controller
class CommentsController < ApplicationController
def create
#articles = Article.find(params[:article_id])
#comment = #articles.comments.create(comment_params)
redirect_to articles_path(#articles)
end
def destroy
#articles = Article.find(params[:article_id])
#comment = #articles.comments.find(params[:id])
#comment.destroy
redirect_to articles_path(#articles)
end
private
def comment_params
params.require(:comment).permit(:commenter, :body)
end
end
routes
Rails.application.routes.draw do
resources :articles do
resources :comments
end
end
When I run the edit blog edit.html.erb it gives me "No route matches [Patch] error. Should I do my routes a different way? I thought resources would cover that. Here is the edit file
<h1>Editing article</h1>
<%= form_for :articles, url: articles_path(#articles), method: :patch do |f| %>
<% if #articles.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#articles.errors.count, "error") %> prohibited
this article from being saved:
</h2>
<ul>
<% #articles.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
Updated with rake routes
Prefix Verb URI Pattern Controller#Action
nba GET /nba(.:format) nba#games
nba_index GET /nba(.:format) nba#index
POST /nba(.:format) nba#create
new_nba GET /nba/new(.:format) nba#new
edit_nba GET /nba/:id/edit(.:format) nba#edit
GET /nba/:id(.:format) nba#show
PATCH /nba/:id(.:format) nba#update
PUT /nba/:id(.:format) nba#update
DELETE /nba/:id(.:format) nba#destroy
article_comments GET /articles/:article_id/comments(.:format) comments#index
POST /articles/:article_id/comments(.:format) comments#create
new_article_comment GET /articles/:article_id/comments/new(.:format) comments#new
edit_article_comment GET /articles/:article_id/comments/:id/edit(.:format) comments#edit
article_comment GET /articles/:article_id/comments/:id(.:format) comments#show
PATCH /articles/:article_id/comments/:id(.:format) comments#update
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
PATCH /articles/:id(.:format) articles#update
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
root GET / welcome#index
I think I found it, in your form_for declaration you specified articles_path rather than article_path. Those are two different methods and they expect different parameters. Use article_path instead and you should get the expected result.
Also, this doesn't make any difference in terms of the computer processing, but you should name your instance variable #article instead of #articles, because it only refers to one object, rather than a list of objects. As you work with Rails (especially the routes, controller names, model names etc.) you'll keep noticing that the framework is very picky about when you use singulars and when you use plurals, which is of course why you made the mistake of using articles_path as explained above.
Rails makes it even more frustrating because they didn't inform you that you were using the wrong method. articles_path doesn't require an article ID, so ideally Rails would raise an error when you gave it one, but it turns out that all the _path and _url route helper methods accept an additional variable so you can define the file extension of the URL (which you would normally define like article_path(#article, "xml").
I'm a beginner in Rails, This is the rails guide blog app. After submitting the form I get No route matches [POST] "/articles/new" which is weird because as you can see from the routes below, articles/new doesn't have a post.
Controller file:
def new
#article = Article.new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def show
#article = Article.find(params[:id])
end
private
def article_params
params.require(:article).permit(:title, :text)
end
Routes file:
Rails.application.routes.draw do
get 'welcome/index'
root 'welcome#index'
resources :articles
Routes:
Prefix Verb URI Pattern Controller#Action
welcome_index GET /welcome/index(.:format) welcome#index
root GET / welcome#index
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
PATCH /articles/:id(.:format) articles#update
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
[EDIT] Here's the form also
<%= form_for :article, url: articles_path do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%=f.submit %>
</p>
<% end %>
Change the form helper to:
<%= form_for #article do |f| %>
You don't need to specify the url if it's the default controller action (articles#create)
Other option:
<%= form_for Article.new do |f| %>
As you're new to Rails, let me give you some ideas
form_for
The problem with this is down to your use of form_for
form_for basically creates a form out of an ActiveRecord object - allowing you to populate various attributes & other elements of the object with a standard method.
Part of this is to create a url component for the form, which will be built from the model_name attribute of your object. Typically, you'll populate the form_for with a pure ActiveRecord object; but as you've just used a symbol, it's going to cause a problem when looking for the url in the non-existent object:
--
Fix
The way to fix this is populate the form_for with an ActiveRecord object:
<%= form_for #article do |f| %>
You've already done most of the work for this - in your controller, you have to declare the #article variable in the new and create actions:
#app/controllers/articles_controller.rb
Class ArticlesController < ApplicationController
def new
#article = Article.new
end
def create
#article = Article.new(article_params)
#article.save
end
private
def article_params
parmas.require(:article).permit(:your, :attributes)
end
end
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.