I am new to Ruby on Rails.I am following Rails Guides tutorial. I've built a basic form which takes title and text as an input and stores in the database.
Here is my code:
ArticlesController:
class ArticlesController < ApplicationController
def new
end
def create
#article = Article.new(article_params)
#article.save
redirect_to #article
end
def show
#article = Article.find(params[:id])
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
routes.rb:
Rails.application.routes.draw do
get 'welcome/index'
root 'welcome#index'
resources :articles
end
new.html.erb(the form):
<h1>New article</h1>
<%= form_with scope: :article, url: articles_path, local: true do |form| %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :text %><br>
<%= form.text_area :text %>
</p>
<p>
<%= form.submit %>
</p>
After I click submit button of the form, I am taken to the show view where I display the data of the form. But I am not able to understand how exactly this is happening? Nowhere have I mentioned to render the show.html view, so how does Rails understand which view I have to render? I am a bit confused with this.
Note: I come from a Django background, so how I would implement routing in Django is by defining the required method(from views.py) in my urls.py for the corresponding route. Then I would render the template defined in the method in views.py.
You have defined resources :articles on your config/routes.rb file which is a rails helper method that generates the following routes when you run rake routes | grep articles on your terminal shell
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 statement redirect_to #article at the end of def create ... end block is translated by rails to 'redirect_to /articles/#article.id' which is responsible for redirecting the response to articles#show action defined in app/controllers/articles_controller.rb
rails g scaffold article title:string text:string
run above command and you will get complete application what you are looking for.
You will understand what is needed in routes.
Please complete the routes guide
But for now as
article GET /articles/:id(.:format)
and in your create action in the last line you wrote
redirect_to #article
which leads to you to the /articles/:id of the instance variable #article
From your code
def create
#article = Article.new(article_params)
#article.save
redirect_to #article
end
after #article is successfully saved, you are redirecting it to show action by specifying redirect_to #article
If you do rake routes
article GET /article/:id(.:format) articles#show
so the actual route for show action is article_path(#article).You can redirect to the show action by writing redirect_to article_path(#article) or even if you simply pass an object (#article) to redirect_to method, rails will redirect it to the corresponding show action because of syntactic sugar of redirect_to url_for(#page)
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 following this tutorial: Getting Started with Rails http://guides.rubyonrails.org/getting_started.html
I have searched on stack: No route matches [POST] “/articles/new” No route matches [POST] "/articles/new" and the recommended spelling correction did not help with my error.
You can find my git: https://github.com/tomile/rails5Blog/tree/adding-partial.
routes.rb
Rails.application.routes.draw do
resources :articles
get 'welcome/index'
root 'welcome#index'
end
articles_controller.rb
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
_form.html.erb (didnt copy paste whole file)
<%= form_for :article do |f| %>
...
<p>
<%= f.submit %>
</p>
<% end %>
new.html.erb
<h1>New Article</h1>
<%= render 'form' %>
<%= link_to 'Back', articles_path %>
$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
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
First thing new route is of type GET.
Second thing is that when we use form_for we provide a instance to it.
So in your articles controller
def new
#article = Article.new
end
and then in form use
<%= form_for #article do |f| %>
It will point the form action to create method of article.
One step of tutorial is missed by you.
You must change first row of form to following:
<%= form_for :article, url: articles_path do |f| %>
After that form works fine.
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