I'm building a forum app where users can create posts and comment them, at this point the post functionally works fine but the comment form only works once and from then on the post page crashes showing the following error:
NoMethodError in Post#show
undefined method `to_key' for #
Did you mean? to_set
to_ary
through rails console i can see that the comment was saved.
here is the terminal error:
ActionView::Template::Error (undefined method `to_key' for #<Comment::ActiveRecord_Relation:0x007fb845e9cca8>
Did you mean? to_set
to_ary):
7: <h3>Reply to thread</h3>
8:
9: <div class="comments_form">
10: <%= form_for #comment, url: new_comments_path(#post), method: :post, remote: true do |f| %>
11: <%= f.label :title %><br>
12: <%= f.text_field :title, placeholder: "Type the comment title here" %><br>
13: <%= f.label :content %><br>
app/views/post/show.html.erb:10:in `_app_views_post_show_html_erb__4054771198415677123_70214711817160'
here is the form:
<%= form_for #comment, url: new_comments_path(#post), method: :post, remote: true do |f| %>
<%= f.label :title %><br>
<%= f.text_field :title, placeholder: "Type the comment title here" %><br>
<%= f.label :content %><br>
<%= f.text_area :content, placeholder: "Type the comment content here" %><br>
<%= f.submit %>
<% end %>
rails mention that error is in this line of the form:
<%= form_for #comment, url: new_comments_path(#post), method: :post, remote: true do |f| %>
the comment_controller.rb:
class CommentController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def index
#comments = Comment.all
end
def new
#comment = Comment.new
end
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(params[:comment].permit(:comment))
#comment.user = current_user
#comment.assign_attributes(comment_params)
if #comment.save
format.html { redirect_to #link, notice: 'Comment was successfully created.' }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
def destroy
#comment.destroy
respond_to do |format|
format.html { redirect_to :back, notice: 'Comment was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_comment
#comment = Comment.find(params[:id])
end
def comment_params
params.require(:comment).permit(:post_id, :content, :title, :user_id)
end
end
the routes.rb:
devise_for :users
root to: 'post#index'
#Posts
get '/posts/new', to: 'post#new'
get '/post/:id', to: 'post#show', as: 'show'
get '/post/:id/edit', to: 'post#edit', as: 'edit'
post '/post', to: 'post#create'
put '/post/:id', to: 'post#update', as: 'update'
delete '/post/:id', to: 'post#destroy', as: 'delete'
#Comments
post '/post/:post_id', to: 'comment#create', as: 'new_comments'
and the post_controller:
class PostController < ApplicationController
def index
if params[:user].blank?
#posts = Post.all.order("created_at DESC")
else
posts = Post.where(user_id: #user_id).order("created_at DESC")
end
end
before_action :authenticate_user!
before_action :find_post, only: [:show, :edit, :update, :destroy]
def show
if Comment.where(post_id: #post.id).present?
#comment = Comment.where(post_id: #post.id)
else
#comment = Comment.new
end
end
def new
#post = Post.new
end
def create
#post = Post.new
#post.user_id = current_user.id.to_i
#Post.create(title: title.string, content: content.string, user_id: current_user.id)
#post.assign_attributes(post_params)
if #post.save
flash[:notice] = "Successfully created post!"
#Post.create(title: title.string, content: content.string, user_id: current_user.id)
redirect_to show_path(#post)
else
flash[:alert] = "Error creating new post!"
render :new
end
end
def edit
end
def update
#post.assign_attributes(post_params)
if #post.changed?
#post.save
redirect_to show_path(#post)
else
render edit_path(#post)
end
end
def destroy
#post.destroy
redirect_to root_path#, notice: “Post destroyed”
end
private
def post_params
params.require(:post).permit(:title, :content, :user_id)
end
def find_post
#post = Post.find(params[:id])
end
end
Thanks in advance for your help.
I think replacing this line:
<%= form_for #comment, url: new_comments_path(#post), method: :post, remote: true do |f| %>
with this:
<%= form_for #post.comments.new, url: new_comments_path(#post), method: :post, remote: true do |f| %>
Should fix the issue!
Related
In ruby on rails i want to show user's articles. Here is my articles_controller.rb
class ArticlesController < ApplicationController
before_action :set_article, only: %i[ show edit update destroy ]
before_action :authenticate_user!, except: [:index, :show ]
before_action :correct_user, only: [:edit, :update, :destroy]
# GET /articles or /articles.json
def index
#articles = Article.all
end
def myarticles
#articles = Article.all
end
# GET /articles/1 or /articles/1.json
def show
end
# GET /articles/new
def new
##article = Article.new
#article = current_user.article.build
end
# GET /articles/1/edit
def edit
end
# POST /articles or /articles.json
def create
##article = Article.new(article_params)
#article = current_user.article.build(article_params)
respond_to do |format|
if #article.save
format.html { redirect_to #article, notice: "Article was successfully created." }
format.json { render :show, status: :created, location: #article }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /articles/1 or /articles/1.json
def update
respond_to do |format|
if #article.update(article_params)
format.html { redirect_to #article, notice: "Article was successfully updated." }
format.json { render :show, status: :ok, location: #article }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
# DELETE /articles/1 or /articles/1.json
def destroy
#article.destroy
respond_to do |format|
format.html { redirect_to articles_url, notice: "Article was successfully destroyed." }
format.json { head :no_content }
end
end
def correct_user
#article = current_user.article.find_by(id: params[:id])
#redirect_to friends_path, notice: "Not Authorized To Edit This Friend" if #friend.nil?
redirect_to articles_path, notice: "Not Authorized To Edit This Article" if #article.nil?
end
private
# Use callbacks to share common setup or constraints between actions.
def set_article
#article = Article.find(params[:id])
end
# Only allow a list of trusted parameters through.
def article_params
params.require(:article).permit(:title, :description, :paragraph, :image, :content, :user_id)
#params.require(:article).permit(:title, :description, :paragraph, :image, :content) eskisi
end
end
in views/articles i have myarticles.html.erb
and in routes i have get 'articles/myarticles'
in myarticles.html.erb i have the same code for show.html.erb(actually i want to show the articles that belongs to that user but i will add that later):
<p id="notice"><%= notice %></p>
<div style="justify-content: center;display: flex;" >
<div style="max-width:680px;width: 100%;" >
<%# <div class="container-{680px}"> %>
<br>
<h1>
<%= #article.title %>
</h1>
<p>
<%= #article.description %>
</p>
<%# <p style="justify-content: center;display: flex;" > %>
<p style="flex-direction: column;display: flex;" >
<%if #article.image.attached? %>
<%=image_tag #article.image ,class:"img-fluid"%>
<% end %>
</p>
<p>
<%= #article.content %>
</p>
<%#
<p>
<%= #article.paragraph %>
<%# </p> %>
<br>
<%= link_to 'Edit', edit_article_path(#article) ,class:"btn btn-secondary"%> |
<%= link_to 'Back', articles_path ,class:"btn btn-secondary"%>
</div>
</div>
But i got this message:
NoMethodError in Articles#myarticles
Showing C:/Users/oem/Desktop/blog/app/views/articles/myarticles.html.erb where line #8 raised:
undefined method `title' for nil:NilClass
<h1>
<%= #article.title %>
</h1>
In your controller actionmyarticles you declared #articles. But in the view you are using #article. #article is available in show where is declared with the before_action callback, but not in my articles.
You probably want to show a list of articles in myarticles view so you can do something like:
<%= #articles.each do |article| %>
<h1>
<%= article.title %>
</h1>
...and so on
<% end %>
I was trying to create associated model Comment for Post via ajax in Rails 5, but get the error.
ArgumentError in Posts#show
Showing /home/mnml/rails/ajax-app/app/views/comments/_form.html.erb where line #2 raised:
wrong number of arguments (given 1, expected 0)
routes.rb
resources :posts, only: [:new, :create, :show, :destroy] do
resources :comments, only: [:new, :create, :show, :destroy]
end
post.rb
belongs_to :user
has_many :comments
comment.rb
belongs_to :user, optional: true
belongs_to :post
posts_controller.rb
def show
#post = Post.find(params[:id])
#comment = #post.comments.build
#comments = #post.comments
end
comments_controller.rb
def new
#post = Post.find(params[:post_id])
#comment = #post.comments.build
end
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(comment_params)
#comment.user_id = current_user.id
respond_to do |format|
if #comment.save
format.html { redirect_to #comment.post, notice: 'Comment was successfully created.' }
#format.json { render #comment, status: :created, location: #comment }
format.js
else
format.html { render :new }
format.json { render json: #comment.errors.full_messages, status: :unprocessable_entity }
end
end
end
private
def comment_params
params.require(:comment).permit(:description)
end
posts/show.html.erb
<%= render "comments/form"%>
comments/_form.html.erb
<form>
<%= form_with [#post, #post.comments.build], id: :new_comment do |form| %>
<div class="form-group">
<%= form.label :description %>
<%= form.text_field :description, id: :comment_description, class: "form-control" %>
</div>
<div class="form-group">
<%= form.submit "Comment it", class: "btn btn-default", data: { "disable-with": "Comment is saving..." } %>
</div>
<% end %>
</form>
comments/create.js.erb
$('#comments').prepend('<%= j render(#comment) %>')
Where I do my mistake? Thanks for help
You need to call form_with like this in your _form.html.erb file
<%= form_with model: [#post, #post.comments.build], id: :new_comment do |form| %>
I have a customer model and book_room model
class Customer < ApplicationRecord
has_many :book_rooms
accepts_nested_attributes_for :book_rooms
end
class BookRoom < ApplicationRecord
belongs_to :customer
end
in the book_room controller the create method is from its parent
class BookRoomsController < ApplicationController
def create
#customer = Customer.find(params[:customer_id])
#customer_room = #customer.book_rooms.create(book_rooms_params)
flash[:notice] = "Customer has been added to room"
redirect_to customer_path(#customer)
end
def destroy
#customer = Customer.find(params[:customer_id])
#customer_room = #customer.book_rooms.find(params[:id])
#customer_room.destroy
flash[:notice] = "Customer room has been deleted"
redirect_to customer_path(#customer)
end
def edit
#customer = Customer.find(params[:customer_id])
end
def update
#customer = Customer.find(params[:customer_id])
#customer.book_rooms.update(book_rooms_params)
flash[:notice] = "Customer has checked out"
redirect_to #customer
end
private
def book_rooms_params
params.require(:book_room).permit(:room, :first_name, :last_name, :phone_number, :checked_out)
end
end
in the Customer show page
<%= form_for [#customer, #customer.book_rooms.build] do |f| %>
<% #room = Room.all %>
<%= f.label "Room: "%>
<%= f.select(:room, #room.collect { |a| [a.room_number, a.id] }) %>
<%= f.submit "Enter" %>
<div class="col-md-12"><%= render #customer.book_rooms.order("created_at DESC") %></div>
This works perfectly and all child objects get created. now when I try to edit the child attributes it doesn't update at all
heres the edit form in the book_room edit page/action
<%= form_for #customer do |f| %>
<%= f.fields_for :book_rooms, #customer.book_rooms do |f| %>
<%= f.check_box :checked_out %>
<% end %>
<%= f.submit "Enter" %>
is there something i am doing wrong? why doesn't it update?
Customers controller
class CustomersController < ApplicationController
before_action :set_customer, only: [:show, :edit, :update, :destroy]
# POST /customers.json
def create
#customer = Customer.new(customer_params)
respond_to do |format|
if #customer.save
format.html { redirect_to #customer, notice: 'Customer was successfully created.' }
format.json { render :show, status: :created, location: #customer }
else
format.html { render :new }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #customer.update(customer_params)
format.html { redirect_to #customer, notice: 'Customer was successfully updated.' }
format.json { render :show, status: :ok, location: #customer }
else
format.html { render :edit }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_customer
#customer = Customer.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def customer_params
params.require(:customer).permit(:first_name, :last_name, :phone_number, :sex, :book_rooms_attributes => [:checked_out])
end
In your customers controller :
Try to change your function customer_params like:
def customer_params
params.require(:customer).permit(:first_name, :last_name, :phone_number, :sex, {:book_rooms => [:checked_out]})
end
For more explications see here
Change your update method to:
def update
#customer = Customer.find(params[:customer_id])
if #customer.update_attributes(customer_params)
flash[:notice] = "Customer has checked out"
redirect_to #customer
else
...redirect to edit page with a flash error message ...
end
end
You also need to modify your edit page.
<%= form_for(:customer, :url => {:action => 'update', :id => #customer.id}, :method => 'PUT') do |f| %>
Try changing the URL to update and changing the method to patch you will go to update method.
<%= form_for :customer, url: customer_path(#customer),method: :patch do |f| %>
<%= f.fields_for :book_rooms, #customer.book_rooms do |f| %>
<%= f.check_box :checked_out %>
<% end %>
<%= f.submit "Enter" %>
My Rails application have two model. Location and Post, Location have many post.I am Using
ancestry gem.
class Post < ActiveRecord::Base
belongs_to :location, :counter_cache => true
end
class Location < ActiveRecord::Base
include Tree
has_ancestry :cache_depth => true
has_many :posts
end
My Post Controller
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.all
end
def show
end
def new
#post = Post.new
end
def edit
end
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render action: 'show', status: :created, location: #post }
else
format.html { render action: 'new' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:name)
end
end
If i am create new Post with which Location belongs in _form.html.erb
<%= form_for(#post) do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved: </h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<%= select :location_id, Location.all.at_depth(4) { |l| [ l.name, l.id ] } %>
<div class="actions">
<%= f.submit %>
</div>
Browser show error message which is display bellow
ArgumentError in Posts#new
Not sure if this fixes your error, but:
To make the dropdown working, change the select line to:
<%= f.select :location_id, Location.all.at_depth(4) { |l| [ l.name, l.id ] } %>
This is because you want the formbuilder f to handle the creation of the form element.
You also have to whitelist the :location_id parameter in the controller:
def post_params
params.require(:post).permit(:name, :location_id)
end
I know that resources should only be nested once, but I have two models that dip into the triple nested waters, which makes things more complex than they need to be, but I do not see a way to avoid it in these two cases...so:
The nesting works like this: group>navbar>links
I am having issues getting the link form to render:
- simple_form_for new_group_navbar_link_path(#group, #navbar, #link) do |f|
%fieldset.well.pleft80.edit
= f.input :method_name
= f.input :text
= f.input :button
.form-actions
= f.submit nil, :class => 'btn btn-primary pull-right btn-large'
navbar belongs_to groups and link belongs_to navbar
Controller:
class LinksController < ApplicationController
before_filter :fetch_group
before_filter :fetch_navbar
before_filter :fetch_link, only: [:show, :edit, :update, :destroy]
def show
end
def new
#link = Link.new
end
def create
#link = #navbar.links.build(params[:link])
if #link.save
redirect_to #navbar, notice: 'link was successfully updated.'
else
render :new
end
end
def edit
#image = #link.build_image unless #link.image
end
def update
respond_to do |format|
if #link.update_attributes(params[:link])
format.html { redirect_to #navbar, notice: 'link was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #link.errors, status: :unprocessable_entity }
end
end
end
def destroy
#link.destroy
redirect_to navbar_path(#navbar)
end
private
def fetch_group
#group = Group.find(params[:group_id])
end
def fetch_navbar
#navbar = Navbar.find(params[:navbar_id])
end
def fetch_link
#link = #navbar.links.find(params[:id])
end
end
Is there something simple I'm overlooking?
just replace
- simple_form_for new_group_navbar_link_path(#group, #navbar, #link) do |f|
with
= simple_form_for new_group_navbar_link_path(#group, #navbar, #link) do |f|