i have two actions in my controller
def up_vote
lesson = Lesson.find(params[:id])
current_user.up_vote!(lesson)
flash[:message] = 'Thanks for voting!'
redirect_to lesson_path(lesson)
end
def down_vote
lesson = Lesson.find(params[:id])
current_user.down_vote!(lesson)
flash[:message] = 'Thanks for voting!'
redirect_to lesson_path(lesson)
end
i was wondering what would be a good way to refactor this (keeping DRY in mind)? i read online that i shouldn't be trying to abuse the before_filter. what else could i use then? thanks!
def vote_up
vote(:up)
end
def vote_down
vote(:down)
end
protected
def vote(direction)
lesson = Lesson.find(params[:id])
current_user.send :"#{direction}_vote!",lesson
flash[:message] = 'Thanks for voting!'
redirect_to lesson_path(lesson)
end
Well most obviously would be to use a single method which takes an up_or_down parameter.
def vote(up_or_down)
lesson = Lesson.find(params[:id])
if up_or_down.eql? "up"
current_user.up_vote!(lesson)
elsif up_or_down.eql? "down"
current_user.down_vote!(lesson)
else
# send an error message or just return
end
flash[:message] = 'Thanks for voting!'
redirect_to lesson_path(lesson)
end
Related
In our Rails app, we have a CalendarsController:
class CalendarsController < ApplicationController
def create
#calendar = current_user.calendars.create(calendar_params)
current_user.add_calendar_and_role(#calendar.id, 'Owner')
if #calendar.save
current_user.total_calendar_count += 1
current_user.owned_calendar_count += 1
current_user.save
flash[:success] = "Calendar created!"
redirect_to dashboard_path
else
render 'static_pages/home'
end
end
def show
#calendar = Calendar.find(params[:id])
#posts = #calendar.posts
#post = Post.new
end
def index
end
def edit
end
def destroy
Calendar.find(params[:id]).destroy
flash[:success] = "Calendar deleted"
redirect_to dashboard_path
end
private
def calendar_params
params.require(:calendar).permit(:name)
end
end
In the create action, when a new #calendar is created, we run #calendar.save to check if the new instance has actually been created, and then perform some actions.
We would like to implement a similar process in our destroy action.
We are thinking of updating the destroy method as follows:
def destroy
#calendar = Calendar.find(params[:id])
#calendar.destroy
if #calendar.delete
flash[:success] = "Calendar deleted"
current_user.total_calendar_count -= 1
if #calendar.administrations.role == "Owner"
current_user.owned_calendar_count -= 1
end
end
redirect_to dashboard_path
end
Is the syntax of this code correct, in particular if #calendar.delete and if #calendar.administrations.role == "Owner"?
And, most importantly, would the code of this destroy action make sense?
Did you think about using the persisted? method
#calendar.destroy
unless #calendar.persisted?
... some code here ....
end
I believe it would be more like:
def destroy
#calendar = Calendar.find(params[:id])
calendar_admin_role = #calendar.administrations.role
if #calendar.destroy
flash[:success] = "Calendar deleted"
current_user.total_calendar_count -= 1
if calendar_admin_role == "Owner"
current_user.owned_calendar_count -= 1
end
end
redirect_to dashboard_path
end
But this is off the top of my head after a long day at work so could be wrong.
I'm trying to send emails through my actionmailer to the commentable owners' email after another user writes them a comment but I keep getting an error. Can someone help me out with this? Thanks in advance.
comment_mailer.rb
def email_notification(member, comment)
#member = commentable.member
#sender = comment.member
mail to: commentable.member.email, subject: "#{comment.member.full_name} (#{comment.member.user_name}) has left you a comment"
end
comment.rb
belongs_to :member
belongs_to :commentable, polymorphic: true
attr_accessible :content
after_create :send_email
def send_email
CommentMailer.email_notification(member, comment).deliver
end
error
undefined local variable or method `comment' for #<Comment:0x51c2ad8>
app/models/comment.rb:18:in `send_email'
app/controllers/comments_controller.rb:20:in `block in create'
app/controllers/comments_controller.rb:19:in `create'
comments_controller
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
klass = [Status, Medium, Project, Event, Listing].detect { |c| params["#{c.name.underscore}_id"] }
#commentable = klass.find(params["#{klass.name.underscore}_id"])
end
def find_member
#member = Member.find_by_user_name(params[:user_name])
end
You error is in the send_email method. There is no local variable called comment. You are already inside an instance of comment, the instance you want to send an email about. So you want to use the keyword self instead.
Change this:
def send_email
CommentMailer.email_notification(member, comment).deliver
end
To this:
def send_email
CommentMailer.email_notification(member, self).deliver
end
self refers to the current instance of comment, which you want to use for your mailer.
I think I'm losing it. I can't figure out why a simple destroy link wont work all of a sudden.
I'm getting this error:
AbstractController::ActionNotFound at /plans/v41w74v2
The action 'destroy' could not be found for PlansController
Plan Controller:
class PlansController < ApplicationController
before_filter :authenticate_user!
def index
#plans = Plan.all
end
def new
#plan = Plan.new
end
def create
#plan = Plan.new(plan_params)
if #plan.save
if #plan.trips.empty?
#possible = #plan.group.trips
render "add_trips"
else
redirect_to plans_path, notice: "Plan successfully created"
end
else
render "new"
end
end
def show
#plan = Plan.find_by_unique_identifier(params[:id])
end
def edit
#plan = Plan.find_by_unique_identifier(params[:id])
#group = #plan.group
#possible = #plan.group.trips
render "add_trips"
end
def update
#plan = Plan.find_by_unique_identifier(params[:id])
if #plan.update_attributes(plan_params)
redirect_to plans_path, notice: "Plan successfully updated!"
else
render "edit"
end
end
def add_trips
#plan = Plan.find_by_unique_identifier(params[:id])
trip.each.update_attributes(plan_id: #plan.id)
redirect_to plans_path, notice: "Trips added to plan"
end
def destory
#plan = Plan.find_by_unique_identifier(params[:id])
#plan.destroy
end
Plan show View:
<%= button_to "Delete", #plan, method: :delete, data: { confirm: "Are you sure you want to delete this plan?"} %>
What am I doing wrong?
Yep. You've got a typo. destory.
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?
I upgraded to rails 4 and now I am no longer able to register users on my app. It seems like my gallery (carrierewave) has broken down. I have inspected the code and can't notice anything that would stop it from working now. I get a undefined method `galleries' and it points to def setup_gallery: self.galleries << Gallery.create and under def create: if #user.save
Fresh eyes on my code would be great.
Users controller:
class UsersController < ApplicationController
respond_to :html, :json
def settings
#user = User.find(id_params)
end
def new
#user = User.new
end
def profile
#profile = User.profile
end
def create
#user = User.new(user_params)
if #user.save
UserMailer.registration_confirmation(#user).deliver
session[:user_id] = #user.id
redirect_to root_url, notice: "Thank you for signing up!"
else
render "new"
end
end
def show
#user = User.find(id_params)
end
def edit
#user = User.find(id_params)
end
def index
#users = User.all
end
def destroy
User.find(id_params).destroy
flash[:success] = "User deleted."
redirect_to users_url
end
def update
#user = if current_user.has_role?(:admin)
User.find(id_params)
else
current_user
end
#user.update_attributes(user_params)
respond_with #user
end
private
def user_params
params.require(:user).permit(:name, :email, :username, :password, :zip_code, :birthday, :role)
end
def id_params
params.require(:id).permit(:name)
end
end
User model:
# models/user.rb
after_create :setup_gallery
def received_messages
Message.received_by(self)
end
def unread_messages?
unread_message_count > 0 ? true : false
end
def unread_messages
received_messages.where('read_at IS NULL')
end
def sent_messages
Message.sent_by(self)
end
# Returns the number of unread messages for this user
def unread_message_count
eval 'messages.count(:conditions => ["recipient_id = ? AND read_at IS NULL", self.user_id])'
end
def to_s; username
end
def has_role?(role_name)
role.present? && role.to_sym == role_name.to_sym
end
def send_password_reset
generate_token(:password_reset_token)
self.password_reset_sent_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
private
def setup_gallery
self.galleries << Gallery.create
end
end
photos controller:
class PhotosController < ApplicationController
def new
#photo = Photo.new
end
def create
#photo = Photo.new(photo_params)
#photo.user = current_user
if #photo.save
flash[:notice] = "Successfully created photos."
redirect_to :back
else
render :action => 'new'
end
end
def edit
#photo = Photo.find(id_params)
end
def update
#photo = Photo.find(id_params)
if #photo.update_attributes(photo_params)
flash[:notice] = "Successfully updated photo."
redirect_to #photo.gallery
else
render :action => 'edit'
end
end
def destroy
#photo = Photo.find(id_params)
#photo.destroy
flash
[:notice] = "Successfully destroyed photo."
redirect_to #photo.gallery
end
private
def user_params
params.require(:user).permit(:name)
end
def id_params
params.require(:id).permit(:name)
end
end
After some trial and error I found that I had to change the private method in the user model.
What works is,
Gallery.create(user: self)
Thanks for those who responded to help!