I am working on a Rails project and I am using namespacing for the models and controllers. That is the child models are put in a directory called user and the controllers are put in a directory called users.
For more clarity, I have a user model that has child admin and student models using Single Table Inheritance (STI). These child models inherit all the attributes of the parent model and can individually define their validations and methods and are placed in a directory called user.
I also have admins_controller and students_controller that use the admin model and the student model respectively. These controllers are placed in a directory called users.
Here's my code;
User model:
class User < ApplicationRecord
has_secure_password
end
Admin model:
class User::Admin < User
end
Student model:
class User::Student < User
end
Admin Controller:
class Users::AdminsController < ApplicationController
before_action :set_admin, only: [:show, :edit, :update, :destroy]
# GET /admins
# GET /admins.json
def index
#admins = User::Admin.all
end
# GET /admins/1
# GET /admins/1.json
def show
end
# GET /admins/new
def new
#admin = User::Admin.new
end
# GET /admins/1/edit
def edit
end
# POST /admins
# POST /admins.json
def create
#admin = User::Admin.new(admin_params)
respond_to do |format|
if #admin.save
format.html { redirect_to users_admin_path(#admin), notice: 'Admin was successfully created.' }
format.json { render :show, status: :created, location: users_admin_path(#admin) }
else
format.html { render :new }
format.json { render json: #admin.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /admins/1
# PATCH/PUT /admins/1.json
def update
respond_to do |format|
if #admin.update(admin_params)
format.html { redirect_to users_admin_path(#admin), notice: 'Admin was successfully updated.' }
format.json { render :show, status: :ok, location: users_admin_path(#admin) }
else
format.html { render :edit }
format.json { render json: #admin.errors, status: :unprocessable_entity }
end
end
end
# DELETE /admins/1
# DELETE /admins/1.json
def destroy
#admin.destroy
respond_to do |format|
format.html { redirect_to users_admins_url, notice: 'Admin was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_admin
#admin = User::Admin.find(params[:id])
end
# Only allow a list of trusted parameters through.
def admin_params
params.require(:admin).permit(:email, :password, :role)
end
end
Routes:
Rails.application.routes.draw do
namespace :users do
resources :admins
resources :students
end
end
index.html.erb:
<p id="notice"><%= notice %></p>
<h1>Admins</h1>
<table>
<thead>
<tr>
<th>Email</th>
<th>Password</th>
<th>Role</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #admins.each do |admin| %>
<tr>
<td><%= admin.email %></td>
<td><%= admin.password %></td>
<td><%= admin.role %></td>
<td><%= link_to 'Show', users_admin_path(admin) %></td>
<td><%= link_to 'Edit', edit_users_admin_path(admin) %></td>
<td><%= link_to 'Destroy', users_admin_path(admin), method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Admin', new_users_admin_path %>
show.html.erb:
<p id="notice"><%= notice %></p>
<p>
<strong>Email:</strong>
<%= #admin.email %>
</p>
<p>
<strong>Password:</strong>
<%= #admin.password %>
</p>
<p>
<strong>Role:</strong>
<%= #admin.role %>
</p>
<%= link_to 'Edit', edit_users_admin_path(#admin) %> |
<%= link_to 'Back', users_admins_path %>
_form.html.erb:
<% if #admin.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#admin.errors.count, "error") %> prohibited this admin from being saved:</h2>
<ul>
<% #admin.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :email %>
<%= form.text_field :email %>
</div>
<div class="field">
<%= form.label :password %>
<%= form.text_field :password %>
</div>
<div class="field">
<%= form.label :role %>
<%= form.text_field :role %>
</div>
<div class="actions">
<%= form.submit %>
</div>
new.html.erb:
<h1>New Admin</h1>
<%= form_with(model: #admin, url: users_admins_path, local: true) do |form| %>
<%= render partial: 'form', admin: #admin, locals: { form: form } %>
<% end %>
<%= link_to 'Back', users_admins_path %>
edit.html.erb:
<h1>Editing Admin</h1>
<%= form_with(model: #admin, url: users_admin_path(#admin), local: true) do |form| %>
<%= render partial: 'form', admin: #admin, locals: { form: form } %>
<% end %>
<%= link_to 'Show', users_admin_path %> |
<%= link_to 'Back', users_admins_path %>
However, when I try creating a new admin or updating an already existing admin, I get the error:
param is missing or the value is empty: admin
I have tried to debug the cause of the issue, but no luck yet. Any form of help will be highly appreciated.
I finally figured it out after careful examination of my logs.
Here's how I solved it:
I examined the request parameters of the create action and I realized that it was of this format:
{"authenticity_token"=>"qJWlHz7Z5myTH3dwNIjjSOzRDY7JN+LoovaG+8dMBnGFRWImJKlWp8cgF7kwTqJXIxqU2fGVkqW9nhOAJ8vFIg==",
"user_admin"=>{"email"=>"promise#gmail.com", "password"=>"[FILTERED]", "role"=>""},
"commit"=>"Create Admin"}
So the request parameters have a hash key of user_admin with values email, password and role, whereas I was passing the admin hash key in my admins_controller.
All I had to do was to modify the admins_params private method in my admins_controller:
From this:
def admin_params
params.require(:admin).permit(:email, :password, :role)
end
To this:
def admin_params
params.require(:user_admin).permit(:email, :password, :role)
end
and that solved the issue.
If you have such an issue, always endeavour to inspect your request parameters in your logs or your application trace. That will give you a lot of information that will help you to resolve the issue.
That's all.
I hope this helps
Related
I'm building an app in which a user can choose from a list of nutrients to add some of them in his personal food diary. Therefore I created a user_nutrients table that holds the user_id, nutrient_id and other information that the user has to type in.
Next to each nutrient item in the list I have a button ("Add this") that redirects the user to the new action of my user_nutrients_controller.rb. So far so good.
I researched now for a few days but did not find a suitable solution to my problem: what do I have to change in my code so that in the user_nutrients/new.html.erb the user does not have to type in the nutrient_id manually but that it automatically holds the id of the nutrient the user selected before in the nutrients/index.html.erb list (through the "Add this" button)?
Every user has_many :user_nutrients and has_many :nutrients, through: :user_nutrients. Every nutrient has_many :user_nutrients and has_many :users, through: :user_nutrients.
Thanks a lot.
Sorry if this question is too simple or not fully understandable. Just started coding few weeks ago.
nutrients/index.html.erb
<% #nutrients.each do |nutrient| %>
<tr>
<td><%= nutrient.id %></td>
<td><%= link_to nutrient.name, nutrient, class: "link" %></td>
<td class="hidden-xs"><%= nutrient.kcal %></td>
<td class="hidden-xs"><%= nutrient.fat %></td>
<td class="hidden-xs"><%= nutrient.carbs %></td>
<td class="hidden-xs"><%= nutrient.sugar %></td>
<td class="hidden-xs"><%= nutrient.protein %></td>
<td class="hidden-xs"><%= nutrient.gram %></td>
<td class="hidden-xs"><%= nutrient.points %></td>
<td>
<div class="dropdown">
<button class="btn btn-default dropdown-toggle btn-xs" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
Actions
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenu1">
<li><%= link_to 'Edit', edit_nutrient_path(nutrient) %></li>
<li role="separator" class="divider"></li>
<li><%= link_to 'Add this', new_user_nutrient_path %></li>
<li role="separator" class="divider"></li>
<li><%= link_to 'Delete', nutrient_path(nutrient), method: :delete, data: {confirm: "Are you sure?"} %></li>
user_nutrients_controller.rb
class UserNutrientsController < ApplicationController
before_action :set_user_nutrient, only: [:show, :edit, :update, :destroy]
# GET /user_nutrients
# GET /user_nutrients.json
def index
#user_nutrients = UserNutrient.where(:user_id => current_user.id).order(day: :desc)
end
# GET /user_nutrients/1
# GET /user_nutrients/1.json
def show
end
# GET /user_nutrients/new
def new
#user_nutrient = UserNutrient.new
end
# GET /user_nutrients/1/edit
def edit
end
# POST /user_nutrients
# POST /user_nutrients.json
def create
#user_nutrient = UserNutrient.new(user_nutrient_params)
#user_nutrient.user = current_user
respond_to do |format|
if #user_nutrient.save
format.html { redirect_to user_nutrients_path, notice: 'User nutrient was successfully created.' }
format.json { render :show, status: :created, location: #user_nutrient }
else
format.html { render :new }
format.json { render json: #user_nutrient.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /user_nutrients/1
# PATCH/PUT /user_nutrients/1.json
def update
respond_to do |format|
if #user_nutrient.update(user_nutrient_params)
format.html { redirect_to #user_nutrient, notice: 'User nutrient was successfully updated.' }
format.json { render :show, status: :ok, location: #user_nutrient }
else
format.html { render :edit }
format.json { render json: #user_nutrient.errors, status: :unprocessable_entity }
end
end
end
# DELETE /user_nutrients/1
# DELETE /user_nutrients/1.json
def destroy
#user_nutrient.destroy
respond_to do |format|
format.html { redirect_to user_nutrients_url, notice: 'User nutrient was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user_nutrient
#user_nutrient = UserNutrient.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_nutrient_params
params.require(:user_nutrient).permit(:user_id, :nutrient_id, :amount, :day)
end
end
_form.html.erb (for user nutrients)
<%= form_for(#user_nutrient) do |f| %>
<% if #user_nutrient.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user_nutrient.errors.count, "error") %> prohibited this user_nutrient from being saved:</h2>
<ul>
<% #user_nutrient.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :nutrient_id %><br>
<%= f.number_field :nutrient_id %>
</div>
<div class="field">
<%= f.label :amount %><br>
<%= f.number_field :amount %>
</div>
<div class="field">
<%= f.label :day %><br>
<%= f.date_select :day %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You want to pass the nutrient_id to the new action in the UserNutrientsController. You could pass it via querystring like this in nutrients#index:
link_to 'Add this', new_user_nutrient_path(nutrient_id: nutrient.id)
The new action would look like this:
def new
#nutrient = Nutrient.find(params[:nutrient_id])
#user_nutrient = UserNutrient.new(nutrient_id: #nutrient.id)
end
The form would look something like this:
<h2>Add Nutrient <%= #nutrient.name %></h2>
<%= form_for(#user_nutrient) do |f| %>
# get rid of number_field for nutrient_id and use a hidden field
<%= f.hidden_field :nutrient_id %>
In my _form partial I render another partial like below
<%= render :partial => 'test', :object => #application.type, \
:locals => {:form => form, \
:application_type => "application[type]"} %>
When I try to load the form I get this error
undefined local variable or method `form' for #<#<Class:0x6daf2c8>:0x8dd3c80>
My test partial
<%= fields_for application_type, application do |application_f| %>
<div>
<div>
<%= application_f.label :uni_id, "University" %>
<%= application_f.collection_select :uni_id, #unis, :id, :check, {:include_blank => true} %>
</div>
</div>
<div>
<% end %>
I recently updated to rails 4.1 from 3.2. It was working before but now it shows error. I guess it is syntax error but could not solve it.
Maybe you need to replace something like this, in your top-level template:
<%= render partial: "form", form: form %>
or like this:
<%= render partial: "form", object: form %>
with something like this (the locals parameter is required now)
<%= render partial: "form", locals: { form: form } %>
Quite a few errors:
<%= render partial: 'test', locals: {form: form }, object: #application %>
<%= form.fields_for application.type, application do |application_f| %>
<div>
<div>
<%= application_f.label :uni_id, "University" %>
<%= application_f.collection_select :uni_id, #unis, :id, :check, {:include_blank => true} %>
</div>
</div>
</div>
<% end %>
This should provide the correct syntax for you.
The error is down to the form variable not being populated. This seems to be from the <%= render call. Without context, the best fix I can give is how it should look:
<%= form_for #variable do |form| %>
<%= render partial: "test", locals: {form:form}, object: #application %>
<% end %>
I experienced this same issue when working on a Rails 6 application
I did an overriding of my routes due to some conflicts from
resources :sessions
to
resources :sessions, as: :sets
Here's how I fixed it:
app/views/sessions/new.html.erb
<h1>New Session</h1>
<%= form_with(model: #session, url: sets_path, local: true) do |form| %>
<%= render partial: 'form', session: #session, locals: { form: form } %>
<% end %>
<%= link_to 'Back', sets_path %>
Note: A URL was defined for the New Form since routing override was done. Thus, the form_with container was isolated from the _form.html.erb partial. This is in a bid to avoid creating multiple _form.html.erb partials for the new.html.erb and edit.html.erb files, since they have different URLs.
app/views/sessions/edit.html.erb
<%= form_with(model: #session, url: set_path(#session), local: true) do |form| %>
<%= render partial: 'form', session: #session, locals: { form: form } %>
<% end %>
<%= link_to 'Show', set_path(session) %> |
<%= link_to 'Back', sets_path %>
Note: A URL was defined for the New Form since routing override was done. Thus, the form_with container was isolated from the _form.html.erb partial. This is in a bid to avoid creating multiple _form.html.erb partials for the new.html.erb and edit.html.erb files, since they have different URLs.
app/views/sessions/_form.html.erb
<% if #session.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#session.errors.count, "error") %> prohibited this session from being saved:</h2>
<ul>
<% #session.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div class="field">
<%= form.label :prefix %>
<%= form.text_field :prefix %>
</div>
<div class="actions">
<%= form.submit %>
</div>
Note: Notice that there is no form helper definition in the _form.html.erb file, it was moved to the new.html.erb and edit.html.erb files, since they now have different URLs due to the modification of their route.
app/views/sessions/index.html.erb
<p id="notice"><%= notice %></p>
<h1>Sessions</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Prefix</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #sessions.each do |session| %>
<tr>
<td><%= session.name %></td>
<td><%= session.prefix %></td>
<td><%= link_to 'Show', set_path(session) %></td>
<td><%= link_to 'Edit', edit_set_path(session) %></td>
<td><%= link_to 'Destroy', set_path(session), method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Session', new_set_path %>
Note: Pay attention to the modification of the link URLs in the new action.
app/views/sessions/show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= #session.name %>
</p>
<p>
<strong>Prefix:</strong>
<%= #session.prefix %>
</p>
<%= link_to 'Edit', edit_session_path(#session) %> |
<%= link_to 'Back', sessions_path %>
Note: Pay attention to the modification of the link URLs in the edit and back actions.
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
before_action :set_session, only: [:show, :edit, :update, :destroy]
# GET /sessions
# GET /sessions.json
def index
#sessions = Session.all
end
# GET /sessions/1
# GET /sessions/1.json
def show
end
# GET /sessions/new
def new
#session = Session.new
end
# GET /sessions/1/edit
def edit
end
# POST /sessions
# POST /sessions.json
def create
#session = Session.new(session_params)
respond_to do |format|
if #session.save
format.html { redirect_to sets_path(#sesion), notice: 'Session was successfully created.' }
format.json { render :show, status: :created, location: sets_path(#sesion) }
else
format.html { render :new }
format.json { render json: #session.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /sessions/1
# PATCH/PUT /sessions/1.json
def update
respond_to do |format|
if #session.update(session_params)
format.html { redirect_to sets_path(#sesion), notice: 'Session was successfully updated.' }
format.json { render :show, status: :ok, location: sets_path(#sesion) }
else
format.html { render :edit }
format.json { render json: #session.errors, status: :unprocessable_entity }
end
end
end
# DELETE /sessions/1
# DELETE /sessions/1.json
def destroy
#session.destroy
respond_to do |format|
format.html { redirect_to sets_url, notice: 'Session was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_session
#session = Session.find(params[:id])
end
# Only allow a list of trusted parameters through.
def session_params
params.require(:session).permit(:name, :prefix)
end
end
Note: Pay attention to the modification of the redirect URLs in the create and update actions.
That's all.
I hope this helps
I am trying to add Tags to my Posts Scaffold using the act_as_taggable Gem but i get an error when i view the index or the show page. I have followed this guide but i still get the error.
here's my code:
posts_controller.rb
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
#posts = Post.tagged_with(params[:tag])
#posts = Post.all.order("created_at DESC")
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
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 :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
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, {image:[]}, :tag_list)
end
end
post.rb
class Post < ActiveRecord::Base
acts_as_taggable
mount_uploaders :image, ImageUploader
end
views/posts/_form.html.erb
<%= form_for(#post , html: { multipart: true }) 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 |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :image %><br>
<%= f.file_field :image , multiple: true %>
</div>
<div class="form-group">
<%= f.label :tag_list, "Tags (separated by commas)" %>
<%= f.text_field :tag_list, class: "form-control" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
views/posts/index.html.erb
<p id="notice"><%= notice %></p>
<h1>Listing Posts</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #posts.each do |post| %>
<tr>
<td><%= post.name %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<%= #posts.tags.each do |tag| %>
<span class="label label-teal">
<%= link_to tag.name, tag_path(tag.name) %>
</span>
<% end %>
<br>
<%= link_to 'New Post', new_post_path %>
views/posts/show.html.erb
<p id="notice"><%= notice %></p>
<%= image_tag #post.image%>
<p>
<strong>Name:</strong>
<%= #post.name %>
</p>
<% #posts.tags.each do |tag| %>
<span class="label label-teal">
<%= link_to tag.name, tag_path(tag.name) %>
</span>
<% end %>
<%= link_to 'Edit', edit_post_path(#post) %> |
<%= link_to 'Back', posts_path %>
config/routes.rb
Rails.application.routes.draw do
resources :posts
get 'tags/:tag', to: 'pins#index', as: :tag
end
Did anyone had a solution to this issue ?
You're calling tags on a collection of Posts, but it's the individual posts that have tags.
Either select a single post and run tags on that, or use Tag.all or something similar to find all tags in the system.
i have a comment system associated to a shipment model in my app where a user can have many shipments and a shipment can have many comments.
Everything is working perfectly the only problem is that i want my whole comment system to be shown in the index page of my model currently it is in the show page.
when i try to put it on the index page i get an error:
undefined method `comments' for nil:NilClass
My Controllers
shipment_controller.rb
class ShipmentsController < ApplicationController
before_action :set_shipment, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
# GET /shipments
# GET /shipments.json
def index
#shipments = Shipment.all
end
# GET /shipments/1
# GET /shipments/1.json
def show
#comments = Comment.where(shipment_id: #shipment)
end
# GET /shipments/new
def new
#shipment = Shipment.new
end
# GET /shipments/1/edit
def edit
end
# POST /shipments
# POST /shipments.json
def create
#shipment = current_user.shipments.new(shipment_params)
respond_to do |format|
if #shipment.save
format.html { redirect_to #shipment, notice: 'Shipment was successfully created.' }
format.json { render :show, status: :created, location: #shipment }
else
format.html { render :new }
format.json { render json: #shipment.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /shipments/1
# PATCH/PUT /shipments/1.json
def update
respond_to do |format|
if #shipment.update(shipment_params)
format.html { redirect_to #shipment, notice: 'Shipment was successfully updated.' }
format.json { render :show, status: :ok, location: #shipment }
else
format.html { render :edit }
format.json { render json: #shipment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /shipments/1
# DELETE /shipments/1.json
def destroy
#shipment.destroy
respond_to do |format|
format.html { redirect_to shipments_url, notice: 'Shipment was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_shipment
#shipment = Shipment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def shipment_params
params.require(:shipment).permit(:name, :description, :from, :to, :date, :pay)
end
end
comments_controller.rb
class CommentsController < ApplicationController
before_action :authenticate_user!
def create
#shipment = Shipment.find(params[:shipment_id])
#comment = Comment.create(params[:comment].permit(:content))
#comment.user_id = current_user.id
#comment.shipment_id = #shipment.id
if #comment.save
redirect_to shipment_path(#shipment)
else
render 'new'
end
end
end
My routes
Rails.application.routes.draw do
devise_for :users, :controllers => {:registrations => "registrations"}
resources :shipments do
resources :comments
end
root 'shipments#index'
end
Shipment View
show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong><%= current_user.full_name %></strong>
</p>
<p>
<strong>Description:</strong>
<%= #shipment.description %>
</p>
<p>
<strong>From:</strong>
<%= #shipment.from %>
</p>
<p>
<strong>To:</strong>
<%= #shipment.to %>
</p>
<p>
<strong>Date:</strong>
<%= #shipment.date %>
</p>
<p>
<strong>Pay:</strong>
<%= #shipment.pay %>
</p>
<div id="comments">
<h2 class="comment_count">
<%= pluralize(#shipment.comments.count, "comment") %>
</h2>
<% #comments.each do |comment| %>
<div class="comment">
<p class="full_name">
<%= comment.user.full_name %>
</p>
<p class="content">
<%= comment.content %>
</p>
</div>
<% end %>
<%= render "comments/form" %>
</div>
<%= link_to 'Edit', edit_shipment_path(#shipment) %> |
<%= link_to 'Back', shipments_path %>
Comments View render
_form.html.erb
<%= simple_form_for([#shipment, #shipment.comments.build]) do |f| %>
<%= f.input :content, label: "Reply to thread" %>
<%= f.button :submit, class: "button" %>
<% end %>
index.html.erb without comments
<h1>Listing Shipments</h1>
<%= link_to "Post a new Shipment", new_shipment_path, class: "btn btn-success" %>
<% #shipments.each do |shipment| %>
<div class="shipment">
<h3><strong><%= shipment.user.full_name%></strong></h3>
<h5><strong>DESCRIPTION: </strong><%= shipment.description %></h5>
<div class="meta">
<%= link_to time_ago_in_words(shipment.created_at) + " ago" %> |
<%= link_to "show", shipment %>
<span class="admin">
| <%= link_to "Edit", edit_shipment_path(shipment) %> |
<%= link_to "Delete", shipment, method: :delete, data: { confirm: "Hey! Are you sure! You wanna delete this shipment??"} %>
</span>
</div>
</div>
<% end %>
index.html.erb with comment system
<h1>Listing Shipments</h1>
<%= link_to "Post a new Shipment", new_shipment_path, class: "btn btn-success" %>
<% #shipments.each do |shipment| %>
<div class="shipment">
<h3><strong><%= shipment.user.full_name%></strong></h3>
<h5><strong>DESCRIPTION: </strong><%= shipment.description %></h5>
<div class="meta">
<%= link_to time_ago_in_words(shipment.created_at) + " ago" %> |
<%= link_to "show", shipment %>
<span class="admin">
| <%= link_to "Edit", edit_shipment_path(shipment) %> |
<%= link_to "Delete", shipment, method: :delete, data: { confirm: "Hey! Are you sure! You wanna delete this shipment??"} %>
</span>
</div>
</div>
<div id="comments">
<h2 class="comment_count">
<%= pluralize(#shipment.comments.count, "comment") %>
</h2>
<% #comments.each do |comment| %>
<div class="comment">
<p class="full_name">
<%= comment.user.full_name %>
</p>
<p class="content">
<%= comment.content %>
</p>
</div>
<% end %>
<%= render "comments/form" %>
<% end %>
After Pavan's Answer
Error
ActiveRecord::RecordNotFound (Couldn't find Shipment with 'id'=):
app/controllers/shipments_controller.rb:9:in `index'
Rendered C:/RailsInstaller/Ruby2.0.0/lib/ruby/gems/2.0.0/gems/actionpack-4.2.3
/lib/action_dispatch/middleware/templates/rescues/_source.erb (1.0ms)
Rendered C:/RailsInstaller/Ruby2.0.0/lib/ruby/gems/2.0.0/gems/actionpack-4.2.3
/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (3.0ms)
Rendered C:/RailsInstaller/Ruby2.0.0/lib/ruby/gems/2.0.0/gems/actionpack-4.2.3
/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
(1.0ms)
Rendered C:/RailsInstaller/Ruby2.0.0/lib/ruby/gems/2.0.0/gems/actionpack-4.2.3
/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within re
scues/layout (36.0ms)
Rendered C:/RailsInstaller/Ruby2.0.0/lib/ruby/gems/2.0.0/gems/web-console-2.2.
1/lib/web_console/templates/_markup.html.erb (1.0ms)
You've got an ivar #comments that doesn't appear to be defined...Try #shipment.comments.each
I want my whole comment system to be shown in the index page of my
model currently it is in the show page
You need to loop through #shipments in the index view like below
<% #shipments.each do |shipment| %>
<% shipment.comments.each do |comment| %>
----rest of the code---
<% end %>
<% end %>
Update:
You are getting the error here in this line <%= pluralize(#shipment.comments.count, "comment") %>. You just need to change it to
<%= pluralize(shipment.comments.count, "comment") %>
And you need to modify the comments iteration part like I said above.
I have two controllers: tasks and workers.
I visited localhost:3000/workers. When I pressed "Add a New Task" (this is the link I put: <%= link_to 'Add a New Task', new_worker_path %>), I got errors:
NoMethodError in Workers#new
Showing /home/alon/projects/todo/app/views/workers/new.html.erb where line #3 raised:
undefined method `tasks_path' for #<#<Class:0xb663ccf0>:0xb663b3c8>
Extracted source (around line #3):
1: <h1>New task</h1>
2:
3: <%= form_for #workers do |f| %>
4: <p>
5: <%= f.label :name %><br />
6: <%= f.text_field :name %>
Rails.root: /home/alon/projects/todo
Application Trace | Framework Trace | Full Trace
app/views/workers/new.html.erb:3:in `_app_views_workers_new_html_erb___132490529__619346358'
app/controllers/workers_controller.rb:28:in `new'
Request
Parameters:
None
Show session dump
Show env dump
Response
Headers:
None
Why did I get these errors?
I created the files _form.html.erb, index.html.erb, new.html.erb, show.html.erb, and edit.html.erb in views/workers.
I defined in routes.rb:
resources :workers do
resources :tasks
end
This is my workers_controller:
class WorkersController < ApplicationController
def index
#workers = Task.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #workers }
end
end
# GET /workers/1
# GET /workers/1.json
def show
#.find(params[:id])
#workers = Task.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #workers }
end
end
# GET /workers/new
# GET /workers/new.json
def new
#workers = Task.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #workers }
end
end
# GET /workers/1/edit
def edit
#worker = Task.find(params[:id])
end
# POST /workers
# POST /workers.json
def create
#worker = Task.new(params[:task])
respond_to do |format|
if #worker.save
format.html { redirect_to #worker, notice: 'Your task was created.' }
format.json { render json: #worker, status: :created, location: #worker }
else
render "new"
end
end
end
# PUT /workers/1
# PUT /workers/1.json
def update
#worker = Task.find(params[:id])
respond_to do |format|
if #worker.update_attributes(params[:task])
format.html { redirect_to #worker, notice: 'Task was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #worker.errors, status: :unprocessable_entity }
end
end
end
# DELETE /workers/1
# DELETE /workers/1.json
def destroy
#worker = Task.find(params[:id])
#worker.destroy
respond_to do |format|
format.html { redirect_to tasks_url }
format.json { head :no_content }
end
end
end
In addition, I wrote the next code in models/tasks.rb:
class Task < ActiveRecord::Base
belongs_to :Worker
attr_accessible :done, :name, :task
end
This is my workers/new.html.erb file:
<h1>New task</h1>
<%= form_for #workers do |f| %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :task %><br />
<%= f.text_area :task %>
</p>
<p>
<%= f.label :done %><br />
<%= f.check_box :done %>
</p>
<p>
<%= f.submit "add a new task" %>
</p>
<% end %>
and this is workers/_form.html.erb:
<%= form_for(#task) do |f| %>
<% if #task.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#task.errors.count, "error") %> prohibited this task from being saved:</h2>
<ul>
<% #task.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>
<div class="field">
<%= f.label :task %><br />
<%= f.text_area :task %>
</div>
<div class="field">
<%= f.label :done %><br />
<%= f.check_box :done %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
If you type rake routes you will see:
$ rake routes
worker_tasks GET /workers/:worker_id/tasks(.:format) tasks#index
POST /workers/:worker_id/tasks(.:format) tasks#create
new_worker_task GET /workers/:worker_id/tasks/new(.:format) tasks#new
...
So new_worker_task will give you a new task for the worker in question when you pass the worker in.
<%= link_to 'Add a New Task', new_worker_task_path(worker) %> # (below)
I recreated your app locally and got it to work with:
<table>
<tr>
<th></th>
<th></th>
<th></th>
</tr>
<% #workers.each do |worker| %>
<tr>
<td><%= link_to 'Show', worker %></td>
<td><%= link_to worker.name, worker %></td>
<td><%= link_to 'Edit', edit_worker_path(worker) %></td>
<td><%= link_to 'New Task', new_worker_task_path(worker) %>
<td><%= link_to 'Destroy', worker, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table>
Note that I added a 'name' attribute for worker to make them easier to show (added it to the form and the index pages and of course a db migration to add it to the db).
As pjammer points out you can also do this through nested_attributes in forms, e.g. form_for([#worker, #task])
you seem to be using nested routes but are passing in Task.new instead of something like Worker.new and if you want to add tasks to the worker, use accepts_nested_attributes_for or create a Form Object to handle the creation of tasks.