#comments nil while #event.comments works in show partial - ruby-on-rails

I cannot figure out why #comments is returning nil when I am attempting to loop through it. If I use #event.comments.each do instead it works just fine. My current structure is User / Events / Comments.
Comments Controller:
class CommentsController < ApplicationController
before_action :authenticate_user!, only: [:create, :destroy]
def create
#event = Event.find(params[:event_id])
#comment = #event.comments.create(comment_params)
#comment.user = current_user
if #comment.save
flash[:notice] = "Comment Added"
redirect_to #event
else
flash[:alert] = "Comment Not Added"
redirect_to #event
end
end
def show
#event = Event.find(params[:id])
#comments = #event.comments
end
def destroy
end
private
def comment_params
params.require(:comment).permit(:body)
end
end
Events Controller Show Action:
class EventsController < ApplicationController
before_action :authenticate_user!, only: [:new, :create,:edit, :update, :show,
:index, :destroy]
def show
#event = Event.find(params[:id])
end
private
def event_params
params.require(:event).permit(:start_date, :start_time, :location, :title, :description, :size, :difficulty,
:activity, :duration)
end
end
Comment Model:
class Comment < ActiveRecord::Base
belongs_to :event
belongs_to :user
validates :body, presence: true
scope :newest, -> { order("created_at DESC") }
end
User Model:
class User < ActiveRecord::Base
has_many :created_events, class_name: 'Event', :foreign_key => "creator_id",
dependent: :destroy
has_many :registers, :foreign_key => "attendee_id", dependent: :destroy
has_many :attended_events, through: :registers, dependent: :destroy
has_many :comments, through: :events
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable
validates :name, presence: true, uniqueness: true, length: { maximum: 50 }
validates :email, presence: true, uniqueness: { case_sensitive: true }
validate :validate_name
def validate_name
if User.where(email: name).exists?
errors.add(:name, :invalid)
end
end
end
Event Model:
class Event < ActiveRecord::Base
scope :latest, -> { order(date: :asc, time: :asc)}
belongs_to :creator, class_name: 'User'
has_many :registers, :foreign_key => 'attended_event_id', dependent: :destroy
has_many :attendees, through: :registers, dependent: :destroy
has_many :comments, dependent: :destroy
validates :title, presence: true, length: { maximum: 50 }
validates :description, presence: true, length: { maximum: 500 }
validates :location, presence: true
validates :start_time, presence: true
validates :start_date, presence: true
validates :activity, presence: true
validates :difficulty, presence: true
end
and lastly, the comments/_show.html.erb partial:
<% if #comments %>
<span class="results-number color-aqua-show">Comments</span>
<% #comments.each do |comment| %>
<p class="comments">
<i class="color-green fa fa-user ride-i"></i>
<%= comment.user.name %>: <%= time_ago_in_words(comment.created_at).capitalize %> ago
</p>
<p>
<i class="color-aqua fa fa-comment ride-i"></i>
<%= comment.body %>
</p>
<div class="bottom-breaker"></div>
<% end %>
<% else %>
<span class="results-number color-aqua-show">Be the first to comment!</span>
<% end %>
Show form from events:
<div class="container s-results margin-bottom-50">
<div class="row">
<div class="col-md-9">
<%= render partial: 'comments/show' %>
<%= render partial: 'comments/form' %>
</div>
</div>
</div>
Again, if I change #comments in the partial to #events.comments it will recognize that there are comments for the particular event and loop through them. This has been driving me insane for the better part of 5 hours now. Thanks.

As Pardeep Saini said, you need to add #comments to events#show:
def show
#event = Event.find params[:id]
#comments = #event.comments
end
The problem is that #comments is a variable, which needs to be defined. If it isn't defined, then you're going to receive the equivalent of an undefined error.
Thus, to fix it, you need to make sure that you're calling a defined variable; either #comments (if you've defined it), or #event.comments.
I think there is a much deeper issue with your structure (from looking at your code).
You'd be better setting it up like this:
#config/routes.rb
resources :events do
resources :comments, only: [:create, :destroy] #-> url.com/events/:event_id/comments...
end
#app/controllers/comments_controller.rb
class EventsController < ApplicationController
def show
#event = Event.find params[:id]
#comments = #event.comments
end
end
This will allow you to use the following:
#app/views/events/show.html.erb
<%= #event.title %>
<%= render #comments %>
<%= render "new_comment" %>
#app/views/events/_comment.html.erb
<%= comment.user.name %>: <%= time_ago_in_words(comment.created_at).capitalize %> ago
<%= comment.body %>
#app/views/events/_new_comment.html.erb
<%= form_for #event.comments.build do |f| %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
This will make it so that if you browse to url.com/events/1, it will output all the event's comments.
The added benefit of this setup is the ability to create / destroy comments:
#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
before_action :set_event
def create
#comment = #event.comments.new comment_params
#comment.user = current_user
#comment.save
end
def destroy
#comment = #event.comments.find params[:id]
#comment.destroy
end
private
def comment_params
params.require(:comment).permit(:body, :user)
end
def set_event
#event = Event.find params[:event_id]
end
end

Solved the problem. It was a very dumb error where I had show listed twice in my events controller. The bottom one was over riding the top.

Related

How can I make my polymorphic model work?

I've got two models User and Image as polymorphic association because I want my image model to reuse in other models.
class User < ApplicationRecord
has_one :cart
has_many :images, as: :imageable, dependent: :destroy
accepts_nested_attributes_for :images
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
before_validation :set_name, on: :create
validates :name, presence: true
private
def set_name
self.name = "person#{rand(1000)}" if self.name.blank?
end
end
class Image < ApplicationRecord
mount_uploader :image, ImageUploader
belongs_to :imageable, polymorphic: true
end
And I made Image polymorphic: true and use carrierwave gem for creating uploader `mount_uploader mount_uploader :image, ImageUploader in Image model:image
class ImageUploader < CarrierWave::Uploader::Base
end
and I permit :image parameters to each model: User and Good,
module Admin
class UsersController < BaseController
before_action :set_admin_user, only: [:show, :edit, :update, :destroy]
def users_list
#admin_users = User.all.preload(:images).where(admin: true)
end
def show
end
def edit
end
def update
if #user.images.update(admin_user_params)
redirect_to admin_users_list_path, notice: 'User was successfully updated'
else
flash[:alert] = 'User was not updated'
end
end
def destroy
end
private
def set_admin_user
#user = User.find(params[:id])
end
def admin_user_params
params.require(:user).permit(:name, :email, images_attributes: [:image])
end
end
end
In my view form I've got the next code:
<%= form_for [:admin, #user], html: { multipart: true } do |f| %>
<%= f.label 'Name', class: 'form-group' %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.fields_for :images_attributes do |i| %>
<%= i.label :image %>
<%= i.file_field :image %>
<% end %>
<%= f.label 'Email', class: 'form-group' %>
<%= f.text_field :email, class: 'form-control' %>
<%= f.submit class: 'btn btn-oultline-primary' %>
<% end %>
but when I want to update user for exampletry to upload the image I've got the next:
Here is what I have as response
I can't saveupload my image. Why is that? I expect to have an insert into db but it doesn't happen and in db I've got no attached images.
Since you are adding multiple images, change your form to:
<%= i.file_field :image, multiple: true, name: "images_attributes[image][]" %>
And in the controller:
def edit
#image = #user.images.build
end
def update
if #user.images.update(admin_user_params)
create_user_images
redirect_to admin_users_list_path, notice: 'User was successfully updated'
else
flash[:alert] = 'User was not updated'
end
end
private
def admin_user_params
params.require(:user).permit(:name, :email, images_attributes: [:id, :user_id, :image])
end
def create_user_images
if params[:images_attributes]
params[:images_attributes]['image'].each do |i|
#image = #user.images.create!(:image => i)
end
end
end
Let me know if you still have problems after the edits :)

Rails simple form undefined method `model_name' for nil:NilClass

I want to create a simple form to make new reviews for a recipe that has been posted in a cookbook. I render the review form on the recipe show page, but it keeps giving me the same error:
undefined method `model_name' for nil:NilClass
When I do not render the partial new review form at app/views/recipes/show.html.erb, but instead I create the file app/views/reviews/new.html.erb, only then the form works. I do not understand why the form is not working when I try to render it at show recipe page.
Here is my code:
Simple form for:
<%= simple_form_for(#review, url: recipe_reviews_path(#recipe)) do |f| %>
<%= f.error_notification %>
<%= f.input :content %>
<%= f.input :rating %>
<%= f.button :submit, class: "btn btn-success" %>
<% end %>
Reviews controller:
class ReviewsController < ApplicationController
def new
#recipe = recipe.find(params[:recipe_id])
#review = Review.new(review_params)
end
def create
#recipe = recipe.find(params[:recipe_id])
#review = Review.new(review_params)
#review.recipe = #recipe
if #review.save
redirect_to recipe_path(#recipe)
else
render 'recipe/show'
end
end
private
def review_params
params.require(:review).permit(:content, :rating)
end
end
Recipes controller:
class RecipesController < ApplicationController
skip_before_action :authenticate_user!
def index
#recipes = Recipe.all
end
def show
#recipe = Recipe.find(params[:id])
#user = User.find(#recipe.user_id)
#full_name = #recipe.user.first_name + " " + #recipe.user.last_name
end
end
Recipe show page:
<div class="review">
<%= render 'review/new' %>
<% #recipe.reviews.each do |review| %>
<%= review.content %>
<%= review.rating %>
<% end %>
</div>
Routes:
resources :recipes, only: [:index, :show] do
resources :reviews, only: [:create]
end
Models:
class Recipe < ActiveRecord::Base
belongs_to :user
has_many :ingredients, dependent: :destroy
has_many :reviews, dependent: :destroy
validates :name, :summary, :course, :kitchen, :photo, :description, presence: true
validates :summary, length: { maximum: 30 }
mount_uploader :photo, PhotoUploader
accepts_nested_attributes_for :ingredients, reject_if: :all_blank, allow_destroy: true
end
model review:
class Review < ActiveRecord::Base
belongs_to :recipe
validates :content, length: { minimum: 20 }
validates :rating, presence: true
validates_numericality_of :rating, :greater_than_or_equal_to => 0, :less_than_or_equal_to => 5
validates :content, presence: true
end
Can anyone see the problem? Thank you in advance!
Just create new instance of Review Modal in show action of RecipesController -:
#review = Review.new
that's all, i will work. :)
Do you have new method in your RecipesController? since you using #recipe in the simpleform view. You need
def new
#recipe = recipe.find(params[:recipe_id])
#review = Review.new(review_params)
end

Rails - nested model input data not appearing in "show" page

I am having trouble figuring out how to make some data collected through a nested model appear on the "show" page. I have a rails app with 3 models, a User model, a Project model, and a Team model. The model associations are as follows:
Project:-
class Project < ActiveRecord::Base
has_many :users, :through => :team
has_one :team, :dependent => :destroy
accepts_nested_attributes_for :team, allow_destroy: true
end
Team:-
class Team < ActiveRecord::Base
belongs_to :project
has_many :users
end
User:-
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_and_belongs_to_many :teams
end
Every project has one team, and every team consists of many users who are already saved in the database. What I would like to do exactly is to make it possible to select multiple existing users within the project form (through a nested form) and save them to a model called team. I managed to get the form working correctly, but im not sure how to go about saving the data collected to the team model, and then to make the group of users that were selected (the team) to appear in project's show page. Please help!
P.S I used the nested form gem to add multiple team members within the project's form.
Projects Show page:-
<%= bootstrap_nested_form_for(#project, :html => {:multipart => true}, layout: :horizontal) do |f| %>
<% f.fields_for :teams do |builder| %>
<% if builder.object.new_record? %>
<%= builder.collection_select :user, User.all, :id, :email, { prompt: "Please select", :selected => params[:user], label: "Employee" } %>
<% else %>
<%= builder.hidden_field :_destroy %>
<%= builder.link_to_remove "Remove" %>
<% end %>
<%= f.link_to_add "Add Team Member", :teams %>
<%= f.submit %>
<% end %>
projects controller:-
class ProjectsController < ApplicationController
before_action :set_project, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#projects = Project.all
respond_with(#projects)
end
def show
respond_with(#project)
end
def new
#project = Project.new
#project.pictures.build
#project.teams.build
respond_with(#project)
end
def edit
#project = Project.find(params[:id])
#project.pictures.build
#project.teams.build
end
def create
#project = Project.new(project_params)
if #project.save
flash[:notice] = "Successfully created project."
redirect_to #project
else
render :action => 'new'
end
end
def update
#project.update(project_params)
respond_with(#project)
end
def destroy
#project.destroy
respond_with(#project)
end
private
def set_project
#project = Project.find(params[:id])
end
def project_params
params.require(:project).permit(:id, :title, :description, :status, :phase, :location, :image, pictures_attributes: [:id, :image], teams_attributes: [:project_id, :user_id])
end
end

Rails - Nested form not showing on "show" page

I am having trouble figuring out how to make some data collected through a nested model appear on the "show" page. I have a rails app with 3 models, a User model, a Project model, and a Team model. The model associations are as follows:
Project:-
class Project < ActiveRecord::Base
has_many :users, :through => :team
has_one :team, :dependent => :destroy
accepts_nested_attributes_for :team, allow_destroy: true
end
Team:-
class Team < ActiveRecord::Base
belongs_to :project
has_many :users
end
User:-
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_and_belongs_to_many :teams
end
Every project has one team, and every team consists of many users who are already saved in the database. What I would like to do exactly is to make it possible to select multiple existing users within the Project form (through a nested form) and save them to a model called Team. I managed to get the form working correctly, but im not sure how to go about saving the data collected to the team model, and then to make the group of users that were selected (the team) to appear in project's show page, as there are 3 models involved. The Please help!
P.S I used the nested form gem to add multiple team members within the project's form.
Projects Show page:-
<%= bootstrap_nested_form_for(#project, :html => {:multipart => true}, layout: :horizontal) do |f| %>
<% f.fields_for :teams do |builder| %>
<% if builder.object.new_record? %>
<%= builder.collection_select :user, User.all, :id, :email, { prompt: "Please select", :selected => params[:user], label: "Employee" } %>
<% else %>
<%= builder.hidden_field :_destroy %>
<%= builder.link_to_remove "Remove" %>
<% end %>
<%= f.link_to_add "Add Team Member", :teams %>
<%= f.submit %>
<% end %>
projects controller:-
class ProjectsController < ApplicationController
before_action :set_project, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#projects = Project.all
respond_with(#projects)
end
def show
respond_with(#project)
end
def new
#project = Project.new
#project.pictures.build
#project.teams.build
respond_with(#project)
end
def edit
#project = Project.find(params[:id])
#project.pictures.build
#project.teams.build
end
def create
#project = Project.new(project_params)
if #project.save
flash[:notice] = "Successfully created project."
redirect_to #project
else
render :action => 'new'
end
end
def update
#project.update(project_params)
respond_with(#project)
end
def destroy
#project.destroy
respond_with(#project)
end
private
def set_project
#project = Project.find(params[:id])
end
def project_params
params.require(:project).permit(:id, :title, :description, :status, :phase, :location, :image, pictures_attributes: [:id, :image], teams_attributes: [:project_id, :user_id])
end
end

"Create" Action for nested resource with multiple Associations in Rails

I have items, that each have multiple (threaded) comments.
The threading is done via a parent key, that points towards another comment.
I just can't get the create action to work properly, I got it far enough to submit into the database, but it didn't have item_id and parent_id set.
I tried form_for [#item, #comment] instead of form_for :comment, url: item_comments_path( #item ) but it didn't help either.
When I look at comment_params in the create action I get this:
Parameters: {"utf8"=>"✓", "comment"=>{"body"=>"examplecommentgoeshere"}, "parent_id"=>"4", "commit"=>"Create Comment", "item_id"=>"4"}
Can anyone help?
Models:
class Item < ActiveRecord::Base
belongs_to :user
has_many :comments, dependent: :destroy
has_many :images, as: :item,
dependent: :destroy
validates :title, presence: true,
allow_blank: false
validates :description, presence: true,
allow_blank: false
validates :user, presence: true,
allow_blank: false
validates :layout, presence: true
end
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :item
has_many :responses, class_name: "Comment",
foreign_key: "parent_id",
dependent: :destroy
has_one :image, as: :item,
dependent: :destroy
belongs_to :parent, class_name: "Comment"
validates :body, presence: true,
allow_blank: false,
length: { minimum: 10 }
end
Comment Controller:
class CommentsController < ApplicationController
before_filter :findParent
before_filter :find, only: [:update, :destroy, :show]
before_filter :is_logged_in?, only: [:create, :update, :destroy]
before_filter :has_permission?, only: [:update, :destroy]
def new
#comment = Comment.new
end
def create
logger.debug comment_params.inspect
#comment = current_user.comments.build(comment_params)
if #comment.save
redirect_to #item
else
logger.debug #comment.errors.inspect
session[:errorbj] = #comment
redirect_to #item
end
end
[...]
private
def comment_params
params.require(:comment).permit(:body, :parent)
end
private
def find
#comment = Comment.find(params[:id])
end
private
def findParent
#item = Item.find params[:item_id]
end
Item View:
<p>
<h3>Add a comment:</h3>
<%= render partial: 'comments/form', locals: { parent: #item } %>
</p>
Partial comments/form:
<%= form_for :comment, url: item_comments_path( #item ) do |f| %>
<p>
<%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.label :image %><br>
<nope>
</p>
<%= hidden_field_tag :parent_id, parent.id %>
<p>
<%= f.submit %>
</p>
<% end %>
From another stackoverflow thread I concluded that the only way to create an object in a multi-association is to do something along the lines of this:
#comment = current_user.comments.build( comment_params.join( { parent_id: <parent.id> } ) )
Other stackoverflow posts however said not to do
#item = Item.new( item_params.join( { user_id: current_user.id } )
So is there really no better way?
i think there are a lot of errors in your code. i hope that i can put that into a form that might help you figure out the fix by yourself:
use form_for [#item, #comment]
findParent should be find_parent
findParent should set a #parent
findParent should find a Comment
the new action should initialize with a parent #comment = Comment.new parent: #parent
hidden_field_tag :parent_id, parent.id should be form.hidden_field :parent
the parent association should be set via comment_params
you don't need the Rails.logger statement, its all in logs/development.log
don't put objects into the session
why is there item and image?
learn more about debugging! http://nofail.de/2013/10/debugging-rails-applications-in-development/
It turns out this is much easier than it seemed.
This is how I ended up doing it:
class CommentsController < ApplicationController
before_filter :findParent, only: [:create]
[...]
def create
#comment = current_user.comments.build(comment_params)
#comment.item = #item
if #comment.save
redirect_to #item
else
session[:errorbj] = #comment
redirect_to #item
end
end

Resources