I'm trying to create a Library Management app and stuck in comment model
So, this is my relationship for comment model:
class User < ApplicationRecord
has_many :comments, dependent: :destroy
end
class Book < ApplicationRecord
has_many :comments, dependent: :destroy
end
class Comment < ApplicationRecord
belongs_to :user
belongs_to :book
validates :content, presence: true, allow_blank: false
end
comments_controller.rb
class CommentsController < ApplicationController
before_action :load_book, only: :create
def index
#q = Comment.ransack(params[:q])
#comments = #q.result.page(params[:page])
end
def new;
end
def create
#comment = Comment.new(comment_params)
#comment.user_id = current_user.id
#comment.book_id = params[:book_id]
if #comment.save
flash[:success] = "create_success"
redirect_to book_path(#book)
end
private
def comment_params
params.require(:comment).permit(:user_id, :book_id, :content)
end
def load_book
#book = Book.find_by(params[:id])
return if #book
flash[:danger] = "books.load_book.error_message"
redirect_to root_path
end
end
in books_controller.rb
def show
#comment = Comment.new
end
app/view/books/show.html.erb
<% provide :title, #book.name %>
<h1><%= #book.name %></h1>
<div class="container">
<dl>
<dt>Author:</dt><dd><%= link_to #book.author.name, #book.author
%></dd><br>
<dt>Category:</dt><dd>
<% #book.categories.each do |c|%>
<%= link_to c.name, c%> |
<% end %>
<dt>Publisher:</dt><dd><%= #book.publisher %></dd><br>
<dt>Page:</dt><dd><%= #book.page %></dd><br>
<dt>Quantity:</dt><dd><%= #book.quantity %></dd><br>
</dl>
<aside>
<section>
<%= render 'comments/form' %>
</section>
</aside>
</div>
app/view/comments/_form.html.erb
<h3>post_comment</h3>
<p>
<%= form_for(#comment) do |f| %>
<%= f.text_area :content %>
<%= f.submit "post", class: "btn btn-primary" %>
<% end %>
</p>
And the browser show this Error:
Missing template comments/new, application/new with {:locale=>
[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb,
:html, :builder, :ruby, :coffee, :jbuilder]}. Searched in: *
"/home/default/ProjectRails/app/views"
This is the first time I make a many to many relationship, is it ok or the problem is in another part ?
As clearly mentioned in the error message
CommentsController#index is missing a template for this request format and variant.
You need to create the file app/view/comments/index.html.erb with some content
Related
I am trying to recover the error message of the validations on my form (there must be no duplicate of ingredient) but I always have a MISSING TEMPLATE that I can not correct, I know that It's a routes problem, but I do not know which one.
I have 3 models, Cocktail Ingrédient and Dose, Dose link Cocktail and Ingredient
ERROR MESSAGE
MISSING TEMPLATE
Missing template cocktails/23 with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]}. Searched in: * "/home/dezrt/code/Pseud0/rails-mister-cocktail/app/views"
doses_controller.rb
class DosesController < ApplicationController
before_action :set_dose, only: [:show, :destroy, :edit]
def index
#doses = Dose.all
end
def show
end
def new
#dose = Dose.new
end
def create
#dose = Dose.create(dose_params)
#cocktail = Cocktail.find(params[:cocktail_id].to_i)
#dose.cocktail = #cocktail
if #dose.save
redirect_to cocktail_path(#dose.cocktail)
else
# params[:dose][:cocktail_id] = #cocktail.id.to_s
#ingredient = Ingredient.find(params[:dose][:ingredient_id].to_i)
render cocktail_path(#cocktail)
end
end
def edit
end
def destroy
#dose.destroy
redirect_to cocktail_path(#dose.cocktail)
end
private
def dose_params
params.require(:dose).permit(:cocktail_id, :ingredient_id, :quantity, :description)
end
def set_dose
#dose = Dose.find(params[:id])
end
end
cocktails_contronller.rb
class CocktailsController < ApplicationController
before_action :set_cocktail, only: [:show]
def index
#cocktails = Cocktail.all
end
def show
#cocktail = Cocktail.find(params[:id])
#dose = Dose.new
#dose.cocktail = Cocktail.find(params[:id])
#ingredient = Ingredient.new
#ingredients = Ingredient.all
end
def new
#cocktail = Cocktail.new
end
def create
#cocktail = Cocktail.create(cocktail_params)
if #cocktail.save
redirect_to cocktail_path(#cocktail)
else
#cocktail = Cocktail.new(cocktail_params)
render :new
end
end
private
def cocktail_params
params.require(:cocktail).permit(:name)
end
def set_cocktail
#cocktail = Cocktail.find(params[:id])
end
end
views/cocktails/show.html.erb
<h1>Cocktail X</h1>
<h2>Voici la listes de tout nos cocktails</h2>
<div class="container">
<h3>Nom du cocktail : <%= #cocktail.name %></h3>
<ul>
<h4>Ingredients : <% #cocktail.doses.each do |dose| %></h4>
<li><%= dose.ingredient.name %> : (<%= dose.quantity %><%= dose.description %>)</li>
<%= link_to dose_path(dose), method: :delete do %>
<i class="fa fa-close"></i>
<% end %>
<% end %>
</ul>
</div>
<%= link_to "Retour aux cocktails", cocktails_path %>
<div class="container">
<h4>Ajouter des ingrédients</h4>
<%= simple_form_for [#cocktail, #dose] do |f| %>
<%= f.input :ingredient_id, collection: #ingredients %>
<%= f.input :quantity, label: 'Quantité', error: 'La quantitée est obligatoire' %>
<%= f.input :description, label: 'Description', error: 'La description est obligatoire' %>
<%= f.button :submit %>
<% end %>
</div>
routes.rb
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root "cocktails#index"
resources :cocktails do
resources :doses, only: [:new, :create, :edit]
end
resources :doses, only: :destroy
end
rails routes
Prefix Verb URI Pattern Controller#Action
root GET / cocktails#index
cocktail_doses POST /cocktails/:cocktail_id/doses(.:format) doses#create
new_cocktail_dose GET /cocktails/:cocktail_id/doses/new(.:format) doses#new
edit_cocktail_dose GET /cocktails/:cocktail_id/doses/:id/edit(.:format) doses#edit
cocktails GET /cocktails(.:format) cocktails#index
POST /cocktails(.:format) cocktails#create
new_cocktail GET /cocktails/new(.:format) cocktails#new
edit_cocktail GET /cocktails/:id/edit(.:format) cocktails#edit
cocktail GET /cocktails/:id(.:format) cocktails#show
PATCH /cocktails/:id(.:format) cocktails#update
PUT /cocktails/:id(.:format) cocktails#update
DELETE /cocktails/:id(.:format) cocktails#destroy
dose DELETE /doses/:id(.:format) doses#destroy
Thanks you for your help !
Missing template cocktails/23 with {:locale=>[:en], :formats=>[:html],
:variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby,
:coffee, :jbuilder]}. Searched in: *
"/home/dezrt/code/Pseud0/rails-mister-cocktail/app/views"
This line render cocktail_path(#cocktail) is the reason for the error. render loads a view. So the input to the render normally should be name of the file, in your case show view of the cocktails. Changing it to render 'cocktails/show' should fix the error.
Also you seems to be confused between render and redirect_to. I suggest you to read render vs redirect
I am trying to use fields_for and create a nested form, however only one text field shows up, blank. I have 3 crewmember records.
crewmember model:
class Crewmember < ActiveRecord::Base
belongs_to :production
belongs_to :callsheet
validates :firstname, presence: true
validates :email, presence: true
def name
"#{firstname} #{lastname}"
end
end
callsheet model
class Callsheet < ActiveRecord::Base
attr_accessible :crewmembers_params
has_many :castmembers
has_many :crewmembers
accepts_nested_attributes_for :crewmembers
end
callsheets controller
class CallsheetsController < ApplicationController
def index
#callsheets = Callsheet.all
#departments = Department.where(production_id: current_user.default_working_production_id)
end
def show
#callsheet = Callsheet.find(params[:id])
end
def new
#callsheet = Callsheet.new
#departments = Department.where(production_id: current_user.default_working_production_id)
end
def edit
#callsheet = Callsheet.find(params[:id])
end
def create
#callsheet = Callsheet.new(callsheets_params)
#Callsheet.production_id = current_user.default_working_production_id
if #callsheets.save
redirect_to callsheet_path
else
render 'new'
end
end
def update
#callsheet = Callsheet.find(params[:id])
if #callsheet.update(callsheets_params)
redirect_to callsheet_path, :notice => "callsheets successfully updated."
else
render 'edit', :notice => "callsheets not updated."
end
end
def destroy
#callsheet = Callsheet.find(params[:id])
#callsheet.destroy
redirect_to callsheets_path
end
private
def callsheets_params
params.require(:callsheet).permit(:crewmembers_params [:id, :firstname])
end
end
form for new callsheet:
<%= form_for #callsheet do |f| %>
<% if #callsheet.errors.any? %>
<div id="error_explanation" class="alert alert-danger">
<strong>
<%= pluralize(#callsheet.errors.count, "error") %> prohibited
this call sheet from being saved:
</strong>
<ul>
<% #callsheet.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.fields_for :crewmember do |crewmember| %>
<fieldset>
<%= crewmember.label :firstname, "First Name" %><br />
<%= crewmember.text_field :firstname %>
</fieldset>
<% end %>
<% end %>
You don't need attr_accessible (that's only for Rails 3).
You should also rename all your models to snake_case, referencing with CamelCase:
#app/models/call_sheet.rb
class CallSheet < ActiveRecord::Base
has_many :cast_members
has_many :crew_members
accepts_nested_attributes_for :crew_members
end
As is the custom with fields_for, you also need to build the associated objects (if you're creating a new record) (you don't need to do this if editing):
#app/controllers/call_sheets_controller.rb
class CallSheetsController < ApplicationController
before_action :set_departments
def new
#callsheet = Callsheet.new
#callsheet.crew_members.build
end
def edit
#callsheet = Callsheet.find params[:id]
end
def update
#callsheet = Callsheet.find params[:id]
#callsheet.update callsheet_params
end
private
def set_departments
#departments = Department.where(production_id: current_user.default_working_production_id)
end
def callsheet_params
params.require(:callsheet).permit(crew_members_attributes: [:id, :firstname])
end
end
This will allow you to use:
<%= form_for #callsheet do |f| %>
<%= f.fields_for :crew_members do |crewmember| %>
<%= crewmember.label :firstname, "First Name" %><br />
<%= crewmember.text_field :firstname %>
<% end %>
<%= f.submit %>
<% end %>
--
When passing nested attributes through fields_for, you need several components:
The correct association in your parent model
An instantiated version of the associated model (#parent.build_child)
Correct fields_for definition
Passing correct parameters through your controller
I've outlined how to achieve the above, all of which you had incorrect.
You can also declare multiple validations in the same call:
#app/models/crew_member.rb
class CrewMember < ActiveRecord::Base
validates :firstname, :email, presence: true
end
Try changing
<%= f.fields_for :crewmember do |crewmember| %>
into
<%= f.fields_for :crewmember, #callsheet.crewmember || #callsheet.build_crewmember do |crewmember| %>
How can I show all comments in the post#show?
comments_controller
#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
#comment = Comment.new(comment_params)
#post = Post.find(params[:post_id])
#comment.user_id = current_user.id
#comment.username = current_user.username
#comment.post_id=#post.id
#comment.save
redirect_to post_path(#post)
end
def show
#comment = Comment.find(params[:id])
end
def comment_params
params.require(:comment).permit(:text, :username)
end
end
Models:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :posts
has_many :comments
end
#app/models/post.rb
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
end
#app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :post
end
the views/posts/show.html.erb
<ul class="img-list-single">
<li>
<a>
<img src=<%= #post.url %>/>
<span class="text-content"><span><%=#post.title%></span></span>
</a>
<%= #comment.username%>
<%if current_user%>
<%= form_for :comment, :url => post_comments_path(#post) do |f|%>
<%= f.text_field :text %>
<%= f.submit%>
<% end %>
<%if current_user.id==#post.user_id%>
<%= button_to 'Delete', #post, method: :delete, :onclick => " returconfirm('Are you sure you want to delete this post?')"%>
<%end%>
<%end%>
First of all fix your posts controller. The show action should look like this:
class PostsController < ApplicationController
def show
#post = Post.find(params[:id])
#comments = #post.comments.includes(:user)
end
end
Now in app/views/posts/show.html.erb, I would render a partial:
<ul>
<%= render #comments %>
</ul>
Rails will look for a partial in app/views/comments/_comment.html.erb. You can just put all your comment view logic in there and will display all the comments:
# app/views/comments/_comment.html.erb
<li>
<%= comment.text %>
<br>
<%= comment.user.try(:username) %>
</li>
Finally, I would fix your create action in the comments controller:
class CommentsController < ApplicationController
def create
# First get the parent post:
#post = Post.find(params[:post_id])
# Then build the associated model through the parent (this will give it the correct post_id)
#comment = #post.comments.build(comment_params)
# Assign the user directly
#comment.user = current_user
if #comment.save
redirect_to post_path(#post)
else
render :new
end
end
end
It seems to me that you don't need to store the username attribute on the comment model, since that should be available through the comment.user association.
in your post#show action simply do:
#post = Post.find(params[:id])
#comments = #post.comments
then in your view add:
<% #comments.each do |comment| %>
<%= comment.text %>
<br />
<% end %>
My link_to in my view is going to a completely different "show.html.erb" than I'd like it to. I'm basically trying to understand why the "link_to #exhibit is linking to an "Investigation" profile. I think it may have to do with my routes file or the fact that its a "belong to" relationship...but can't seem to get it workin...what should that link_to be?
UPDATE: (AS PER BROIS QUESTION)
The missing misbehaving link_to is in the <%= link_to #exhibit do %> in show.html.erb
MY EXHIBIT.RB (MODEL)
class Exhibit < ActiveRecord::Base
attr_accessible :content, :investigation_id, :name, :user_id, :media, :media_html
belongs_to :investigation
has_many :categorizations
has_many :categories, :through => :categorizations
validates :name, presence: true, length: { maximum: 140 }
validates :content, presence: true
default_scope -> { order('created_at DESC') }
auto_html_for :media do
html_escape
image
youtube(:width => 400, :height => 250)
link :target => "_blank", :rel => "nofollow"
simple_format
end
MY EXHIBIT CONTROLLER:
class ExhibitsController < ApplicationController
include AutoHtml
def new
#exhibit = Exhibit.new
end
def show
#exhibit = Exhibit.find(params[:id])
end
def index
#exhibits = Exhibit.paginate(page: params[:page])
end
def create
#investigation = Investigation.find(params[:investigation_id])
#exhibit = #investigation.exhibits.create(params[:exhibit])
if #exhibit.save
flash[:success] = "You've successfully added etc etc..."
redirect_to investigation_path(#investigation)
else
render 'new'
end
end
end
MY ROUTES.RB
resources :sessions, only: [:new, :create, :destroy]
resources :investigations do
resources :players
end
resources :investigations do
resources :exhibits
end
LASTLY MY SHOW.HTML.ERB (INVESTIGATION PROFILE)
<% #investigation.exhibits.each do |exhibit| %>
<div class="row-fluid services_circles">
<%= link_to #exhibit do %>
<div class="media">
<div class="pull-left">
<%= exhibit.media_html %>
</div>
<div class="media-body">
<h4 class="media-heading"><%= exhibit.name %></h4>
<p><%= exhibit.content %></p>
</div>
</div>
<% end %>
<% end %>
ADDED THE INVESTIGATIONS CONTROLLER
class InvestigationsController < ApplicationController
def new
#investigation = Investigation.new
end
def show
#investigation = Investigation.find(params[:id])
end
def index
#investigations = Investigation.paginate(page: params[:page])
end
def create
#investigation = Investigation.new(params[:investigation])
if #investigation.save
flash[:success] = "You've successfully created..."
redirect_to #investigation
else
render 'new'
end
end
end
ADDED THE INVESTIGATION MODEL
class Investigation < ActiveRecord::Base
# belongs_to :user
has_many :players, dependent: :destroy
has_many :exhibits, dependent: :destroy
default_scope -> { order('created_at DESC') }
end
I appreciate the help...if i need to post any more info just let me know
IN YOUR : app/contorollers/exhibits_controller.rb
def show
#investigation = Investigation.find(params[:investigation_id])
#exhibit = Exhibit.find(params[:id])
end
IN YOUR : app/views/exhibits/show.html.erb
<%= link_to investigation_exhibit_path(#investigation, #exhibit) do %>
Maybe, I think.
I've run into an issue with my Ruby on Rails app. I've a page called /discussion which contains discussions that users can comment on with microposts. The goal here is to have a form below each micropost that, when submitted, will put the text in the discussion. The form shows up - but whenever I click submit I get the error:
NoMethodError in MicropostsController#create
undefined method `micropost' for #<User:0x007f9744091680>
Rails.root: /home/nick/Documents/RailsProjects/buon
Application Trace | Framework Trace | Full Trace
app/controllers/microposts_controller.rb:8:in `create'
the micropost controller
class MicropostsController < ApplicationController
before_filter :signed_in_user, only: [:create, :destroy]
def index
end
def create
#micropost = current_user.micropost.build(params[:micropost])
if #micropost.save
flash[:success] = "Posted!"
redirect_to root_url
else
render 'static_pages/home'
end
end
def destroy
end
end
the _discusions.html
<% content_for :script do %>
<%= javascript_include_tag 'hover_content' %>
<% end %>
<li>
<div class = "intro-bar"><span class = "intro"><%=discussion.intro %></span></div>
<div class = "content-bar"><span class = "content"><%= discussion.content %></span></div>
<span class = "timestamp">
Posted <%= time_ago_in_words(discussion.created_at) %> ago.
</span>
</li>
<% if signed_in? %>
<div class = "row">
<aside class = "span4">
<section>
<%= render 'shared/micropost_form', :locals => {:discussion => discussion }%>
</section>
</aside>
</div>
<% end %>
the micropost model
class Micropost < ActiveRecord::Base
attr_accessible :break_votes, :content, :not_votes
belongs_to :user
belongs_to :discussion
validates :content, presence: true, length: { maximum: 200 }
validates :user_id, presence: true
default_scope order: 'microposts.created_at DESC'
end
any ideas?
If this is a has_many association you need to pluralize, so your code should read:
#micropost = current_user.microposts.build(params[:micropost])