I have a working commenting system that is polymorphic so that comments can be added to users and posts. However, I am unable to figure out how to attach the logged in user (commenter) to the comment.
comments_controller.rb:
class CommentsController < ApplicationController
before_filter :authenticate_user!, :only => [:create, :destroy]
def index
#commentable = find_commentable
#comments = #commentable.comments
end
def new
#commentable = find_commentable
end
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment])
if #comment.save
flash[:notice] = "Successfully created comment."
redirect_to get_master
else
render :action => 'new'
end
end
def destroy
#comment = Comment.find(params[:id])
#comment.destroy
respond_to do |format|
format.html { redirect_to comments_url }
format.json { head :no_content }
end
end
protected
def find_commentable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
def get_master
#parent = #comment.commentable
if #parent.respond_to?('commentable_type')
#comment = #parent
get_master
else
return #parent
end
end
end
Isn't it as simple as adding it before the save?
#comment.commenter = current_user
You can also add it in your view:
f.hidden_field :commenter_id, value: current_user.id
I think I'd prefer setting it in the view.
Related
The following code creates a select box
<%= select_tag "microposts", options_from_collection_for_select(#microposts, "id", "name"), { :prompt => 'All microposts' } %>
I want to show all the microposts in a select box, but i get the following error
NoMethodError in Managments#edit
undefined method `map' for nil:NilClass
Did you mean? tap
Can someone explain to me how to display all the microposts in a select box?
controller
class ManagmentsController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
def index
#managments = current_user.managments
#micropost = current_user.microposts.build
end
def show
#microposts = Micropost.paginate(page: params[:page])
#managment = Managment.find_by(id: params[:id])
if !#managment
raise ActionController::RoutingError.new('Not Found')
end
#user = #managment.user
end
def new
#user = User.new
#managment = Managment.new
end
def edit
#managment = Managment.find(params[:id])
end
def create
#managment = current_user.managments.build(managment_params)
if #managment.save
flash[:success] = "Managment created!"
redirect_to #managment
else
#feed_items = current_user.feed.paginate(page: params[:page])
render 'new'
end
end
def update
#managment = Managment.find(params[:id])
if #managment.update(managment_params)
redirect_to #managment
else
render 'edit'
end
end
def destroy
#managment.destroy
flash[:success] = "Managment deleted"
redirect_to managments_path
end
private
def managment_params
params.require(:managment).permit(
:title, :budget,
:procent1, :procent2, :procent3, :procent4,
:procent5, :procent6, :procent7,
:procent8, :procent9, :procent10,
:procent11, :procent12, :result1,
:result2, :result3, :objectivesname1,
:objectivesname2, :objectivesname3,
:lowprocent1, :lowprocent2, :lowprocent3,
:medprocent1, :medprocent2, :medprocent3,
:highprocent1, :highprocent2, :highprocent3,
:lowobjectives1, :lowobjectives2, :lowobjectives3,
:medobjectives1, :medobjectives2, :medobjectives3,
:highobjectives1, :highobjectives2, :highobjectives3
)
end
def correct_user
#managment = current_user.managments.find_by(id: params[:id])
redirect_to managments_path if #managment.nil?
end
end
The Answer to the question can be find in the comments
def edit
#managment = Managment.find(params[:id])
#microposts = Micropost.paginate(page: params[:page])
end
I created a feed following http://railscasts.com/episodes/406-public-activity?view=asciicast.
In that feed I'd like it to say,
"User Name" added/updated value "Value Name" with the comment "Comment Content".
This partial creates the "Value Name" part:
views/public_activity/comment/_create.html.erb
added value
<% if activity.trackable %>
<b><%= link_to activity.trackable.name, activity.trackable %></b>
<% else %>
which has since been removed
<% end %>
This partial creates the "Comment Content" part:
views/public_activity/valuation/_create.html.erb
with the comment
<% if activity.trackable %>
<%= link_to activity.trackable.content %>
<% else %>
which has since been removed
<% end %>
If I add name or content to either one of the partials I am given an undefined method error message. What code would I need to add to their controllers or application controller to make something like this work?
Ideally, with the comment "Comment Content". would only be generated in instances where a comment is created so that, with the comment, wouldn't be left hanging.
class CommentsController < ApplicationController
before_action :load_commentable
before_action :set_comment, only: [:show, :edit, :update, :destroy]
before_action :logged_in_user, only: [:create, :destroy]
def index
#comments = #commentable.comments
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(comment_params)
if #comment.save
#comment.create_activity :create, owner: current_user
redirect_to #commentable, notice: "comment created."
else
render :new
end
end
def edit
#comment = current_user.comments.find(params[:id])
end
def update
#comment = current_user.comments.find(params[:id])
if #comment.update_attributes(comment_params)
redirect_to #commentable, notice: "Comment was updated."
else
render :edit
end
end
def destroy
#comment = current_user.comments.find(params[:id])
#comment.destroy
#comment.create_activity :destroy, owner: current_user
redirect_to #commentable, notice: "comment destroyed."
end
private
def set_comment
#comment = Comment.find(params[:id])
end
def load_commentable
resource, id = request.path.split('/')[1, 2]
#commentable = resource.singularize.classify.constantize.find(id)
end
def comment_params
params.require(:comment).permit(:content, :commentable)
end
end
class ValuationsController < ApplicationController
before_action :set_valuation, only: [:show, :edit, :update, :destroy]
before_action :logged_in_user, only: [:create, :destroy]
def index
if params[:tag]
#valuations = Valuation.tagged_with(params[:tag])
else
#valuations = Valuation.order('RANDOM()')
end
end
def show
#valuation = Valuation.find(params[:id])
#commentable = #valuation
#comments = #commentable.comments
#comment = Comment.new
end
def new
#valuation = current_user.valuations.build
end
def edit
end
def create
#valuation = current_user.valuations.build(valuation_params)
if #valuation.save
redirect_to #valuation, notice: 'Value was successfully created'
else
#feed_items = []
render 'pages/home'
end
end
def update
if #valuation.update(valuation_params)
redirect_to #valuation, notice: 'Value was successfully updated'
else
render action: 'edit'
end
end
def destroy
#valuation.destroy
redirect_to valuations_url
end
private
def set_valuation
#valuation = Valuation.find(params[:id])
end
def correct_user
#valuation = current_user.valuations.find_by(id: params[:id])
redirect_to valuations_path, notice: "Not authorized to edit this valuation" if #valuation.nil?
end
def valuation_params
params.require(:valuation).permit(:name, :private_submit, :tag_list, :content, :commentable, :comment)
end
end
class ApplicationController < ActionController::Base
include PublicActivity::StoreController
#before_action :load_todays_habits
before_action :set_top_3_goals
before_action :randomize_value
before_action :set_stats
protect_from_forgery with: :exception
include SessionsHelper
def set_top_3_goals
#top_3_goals = current_user.goals.unaccomplished.top_3 if current_user
end
def randomize_value
#sidebarvaluations = current_user.valuations.randomize if current_user
end
def set_stats
#quantifieds = Quantified.joins(:results).all
#averaged_quantifieds = current_user.quantifieds.averaged if current_user
#instance_quantifieds = current_user.quantifieds.instance if current_user
end
hide_action :current_user
private
#def load_todays_habits
# #user_tags = current_user.habits.committed_for_today.tag_counts if current_user
# #all_tags = Habit.committed_for_today.tag_counts if current_user
#end
# Confirms a logged-in user.
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
end
Thank you so much for your time.
In my app I have a commenting system that's largely based off of this railscast. Now in my models I'm changing the to_param to a random string so the id isn't in the url. But then that breaks commenting.
status.rb
class Status < ActiveRecord::Base
attr_accessible :content, :member_id, :document_attributes, :permalink
belongs_to :member
belongs_to :document
has_many :comments, as: :commentable, dependent: :destroy
before_create :make_it_permalink
accepts_nested_attributes_for :document
def to_param
permalink
end
private
def make_it_permalink
# this can create permalink with random 12 digit alphanumeric
self.permalink = SecureRandom.hex(12)
end
end
statuses_controller.rb
class StatusesController < ApplicationController
before_filter :authenticate_member!, only: [:index, :new, :create, :destroy]
before_filter :find_member
rescue_from ActiveRecord::RecordNotFound do
render file: 'public/404', status: 404, formats: [:html]
end
def index
#statuses = Status.order('created_at desc').page(params[:page]).per_page(21)
respond_to do |format|
format.html # index.html.erb
format.js
end
end
def show
#status = Status.find_by_permalink(params[:id])
#commentable = #status
#comments = #commentable.comments.order('created_at desc').page(params[:page]).per_page(15)
#comment = #commentable.comments.new
respond_to do |format|
format.html # show.html.erb
format.json { redirect_to profile_path(current_member) }
end
end
def new
#status = Status.new
#status.build_document
respond_to do |format|
format.html # new.html.erb
format.json { render json: #status }
format.js
end
end
def create
#status = current_member.statuses.new(params[:status])
respond_to do |format|
if #status.save
#activity = current_member.create_activity(#status, 'created')
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to profile_path(current_member), alert: 'Post wasn\'t created. Please try again and ensure image attchments are under 10Mbs.' }
format.json { render json: #status.errors, status: :unprocessable_entity }
format.js
end
end
end
def destroy
#status = current_member.statuses.find(params[:id])
#activity = Activity.find_by_targetable_id(params[:id])
#commentable = #status
#comments = #commentable.comments
if #activity
#activity.destroy
end
if #comments
#comments.destroy
end
#status.destroy
respond_to do |format|
format.html { redirect_to profile_path(current_member) }
format.json { head :no_content }
end
end
private
def find_member
#member = Member.find_by_user_name(params[:user_name])
end
def find_status
#status = current_member.statuses.find_by_permalink(params[:id])
end
end
comments_controller.rb
class CommentsController < ApplicationController
before_filter :authenticate_member!
before_filter :load_commentable
before_filter :find_member
def index
redirect_to root_path
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(params[:comment])
#comments = #commentable.comments.order('created_at desc').page(params[:page]).per_page(15)
#comment.member = current_member
respond_to do |format|
if #comment.save
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to :back }
format.json
format.js
end
end
end
def destroy
#comment = Comment.find(params[:id])
respond_to do |format|
if #comment.member == current_member || #commentable.member == current_member
#comment.destroy
format.html { redirect_to :back }
format.json
format.js
else
format.html { redirect_to :back, alert: 'You can\'t delete this comment.' }
format.json
format.js
end
end
end
private
# def load_commentable
# resource, id = request.path.split('/')[1,2] # photos/1/
# #commentable = resource.singularize.classify.constantize.find(id) # Photo.find(1)
# end
# alternative option:
def load_commentable
klass = [Status, Medium, Project, Event, Listing].detect { |c| params["#{c.name.underscore}_id"] }
#commentable = klass.find(params["#{klass.name.underscore}_id"])
end
#def load_commentable
# #commentable = params[:commentable_type].camelize.constantize.find(params[:commentable_id])
#end
def find_member
#member = Member.find_by_user_name(params[:user_name])
end
end
The problem lies in the load_commentable method in the comments_controller. I've tried a couple different variations of the method but the second one works best for my app and it was working when the url's had their id's in them. But since I overwrote the to_param to use my random permalink commenting stopped working because it's trying to find theid where it equals the permalink. Since it seems to try to find the id through the url, how do I pass the the actual id and not the permalink or how do I find commentable by it's permalink instead of id?
It's hard to tell if your param will always be the value of id or always be the permalink, or will sometimes be an id and sometimes a permalink.
If it will always be a permalink, then do:
#commentable = klass.find_by_permalink(params["#{klass.name.underscore}_id"])
instead of
#commentable = klass.find(params["#{klass.name.underscore}_id"])
If it is sometimes id and sometimes other, then you will need make logic to determine which is needed based on the class.
I've implemented polymorphic commenting based off the Ryan Bates Railscast and everything is working correctly so far, but I'm trying to scope the delete action so that only the owner of the comment can delete their own comments and the owner of the commentable can delete any comment. I'm not sure how to make this happen.
Any ideas?
Here's my CommentsController:
class CommentsController < ApplicationController
before_filter :authenticate_member!
before_filter :load_commentable
def index
#comments = #commentable.comments
#comment = #commentable.comments.new
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(params[:comment])
#comment.member = current_member
if #comment.save
redirect_to :back
else
render :new
end
end
def destroy
#comment = Comment.find(params[:id])
#comment.destroy
if #comment.destroy
redirect_to :back
else
format.html { redirect_to :back, alert: 'You can\'t delete this comment.' }
end
end
private
# def load_commentable
# resource, id = request.path.split('/')[1,2] # photos/1/
# #commentable = resource.singularize.classify.constantize.find(id)
# Photo.find(1)
# end
# alternative option:
def load_commentable
klass = [Status, Medium].detect { |c| params["#{c.name.underscore}_id"] }
#commentable = klass.find(params["#{klass.name.underscore}_id"])
end
end
You could set up your destroy method as follows:
def destroy
#comment = Comment.find(params[:id])
if #comment.user == current_user
#comment.destroy
format.html { redirect_to :back, alert: "Comment Successfully destroyed" }
else
format.html { redirect_to :back, alert: 'You can\'t delete this comment.' }
end
end
If you want to allow your admin to delete any comments, you can change
if #comment.user == current_user
to
if #comment.user == current_user || current_user.admin?
class CommentsController < ApplicationController
def create
#contact = Contact.find(params[:contact_id])
#comment = #contact.comments.create(params[:comment])
respond_to do |format|
format.html { redirect_to contact_path(#contact) }
format.js
end
end
def destroy
#contact = Contact.find(params[:contact_id])
#comment = #contact.comments.find(params[:id])
#comment.destroy
respond_to do |format|
format.html { redirect_to contact_path(#contact) }
format.js
end
end
end
Is it possible to also create and destroy comments for the company model? How do you check whether a user is on a certain page? Because then I can just have an if statement.
The changed CommentsController
class CommentsController < ApplicationController
def create
#object = find_object
#comment = #object.comments.create(params[:comment])
respond_to do |format|
format.html { redirect_to [#object] }
format.js
end
end
def destroy
#object = find_object
#comment = object.comments.find(params[:id])
#comment.destroy
respond_to do |format|
format.html { redirect_to [#object] }
format.js
end
end
private
def object
#object = if params[:contact_id]
Contact.find(params[:contact_id]
elsif params[:company_id]
Company.find(params[:company_id])
end
end
end
you can do it with routing
# routes.rb
resources :contacts do
resources :comments
end
resources :company do
resources :comments
end
So in controller you can handle if there any company or contact around:
def destroy
#object = find_object
#comment = #object.comments.find(params[:id])
#comment.destroy
redirect_to [#object]
end
private
def find_object
#object = if params[:contact_id]
Contact.find(params[:contact_id])
elsif params[:company_id]
Company.find(params[:company_id])
end
end
But best solution here is to use POLYMORPHISM here. Check out:
http://railscasts.com/episodes/154-polymorphic-association