How to destroy polymorphic model? Method destroy missing argument - ruby-on-rails

Im using this gem to add private messages to my application.
https://github.com/LTe/acts-as-messageable/blob/master/lib/acts-as-messageable/message.rb
I`m trying to add remove link to message.
So in my controller i have destroy action:
def destroy
#message = current_user.messages.with_id(params[:id])
if #message.destroy
flash[:notice] = "All ok"
else
flash[:error] = "Fail"
end
end
And in my view i have link: = link_to "Delete", message_path(message.id), :method => :delete
But when im trying to click link i receive: wrong number of arguments (0 for 1)
This is related with this question: Why delete method gives me wrong path? with

The problem is that you're getting all messages, so #message is really multiple messages. You probably want to do:
#message = Message.find(params[:id])
But this may be different for the gem. The gem's documentation has a section on deleting at the bottom of the readme.

Related

Destroy user - with custom authentication (rails)

Quick question: I was following this tutorial where they built user authentication system instead of using devise.
My issue is the tutorial misses the destroy action in which devise has ready and does so well.
My create action is
User_controller.rb
def create
#user = User.create(user_params)
session[:user_id] = #user.id
if #user.valid?
flash[:notice] = "You've successfully Created Your Account! Welcome!"
redirect_to root_path
else
flash[:notice] = "Opps Something went bad, :/ Try again please"
render action: 'new'
end
end
I really hope this is not a total nuub question event though I am one. But can somebody offer some tips for a destroy action ? and also how would that action appear in routes and through a link_to method. I want to create a deactivate page that gives a send off and the user is able to cancel their account. Any cool tips toward the deactivate page on the side will be much appreciated.
The Hartl rails tutorial covers this quite well IMO. Once you have the destroy action defined in your controller, you could create a link to deactivate their account calling the destroy action and redirect to the home page, or a goodbye page. As long as users is listed as a resource in your routes, you shouldn't need to modify your routes as DELETE is a standard CRUD command.
https://www.railstutorial.org/book/updating_and_deleting_users
for example:
user_controller
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_url
end
view
<%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
For the deactivate page, maybe you can add a boolean column in your users table, say is_active,
and another controller action for deactivation, say deactivate, which will just set the is_active column as false for that user.
see sample routes.rb for the route.
#ncarroll 's sample is correct, for the routes, if you have in your routes.rb:
Rails.application.routes.draw do
resources :users do
put :deactivate
end
end
This will automatically create routes for the RESTful actions, which includes destroy.

NoMethodError in ConfirmationController

I have been trying to solve the following problem for a couple of days. Forgive me if this is a common problem as I am new to rails and probably couldn't query the right question/keyword in stackoverflow or google.
I am building a system where a user will get an invite via email, click on a unique link, be taken to a page where he/she can accept or decline the invitation. I am getting stuck at the part where the user accepts or declines the invitation.
I've built it around two controllers: an invitations controller and a confirmations controller.The invitations controller creates a record containing a name, an email, and a uniquely generated token. The controller then emails a link with the token to the defined email. The link points to the confirmations controller and passes the unique token from the invitation. However, when clicking on the link and accepting the invitation, I get the following error:
NoMethodError in ConfirmationController#confirm
undefined method `update_attribute' for nil:NilClass
Here is some of the code for solving this issue:
Confirmation_controller.rb
class ConfirmationController < ApplicationController
def new
#confirmation = Invitation.find_by_invite_token(params[:invite_token])
end
def confirm
if #confirmation.update_attribute(:accepted, true)
flash[:success] = "Invitation confirmed!"
redirect_to 'static_pages/home'
else
flash[:notice] = "Failed :("
redirect_to 'static_pages/home'
end
end
end
routes.rb
match '/confirmation/:invite_token', to: 'confirmation#new'
match '/confirmation/:invite_token/confirm', to: 'confirmation#confirm'
app/views/confirmation/new.html.erb
Click here to accept:
<%= link_to "Confirm", :controller => "confirmation", :action => "confirm" %>
You need to get your Invitation in the confirm method too.
If you want rails to raise an exception if no invitation was found
def confirm
#confirmation = Invitation.find_by_invite_token!(params[:invite_token])
#confirmation.update_...
end
No exception will be raise. You may want to check manually with a condition in the following case.
def confirm
#confirmation = Invitation.find_by_invite_token(params[:invite_token])
if #confirmation
#confirmation.update_...
else
# do something
end
end
You should find confirmation record before calling update_attribute on it, like you did it in new action:
#confirmation = Invitation.find_by_invite_token(params[:invite_token])
Or, to throw exception when the record is not found and to render 404 page to the user:
#ocnfirmation = Invitation.find_by_invite_token!(params[:invite_token])
The problem is that you never told the program what #confirmation is. What you should do is find it first then run the update. Note this is different from the different answers, just thought I would throw in some variety.
def confirm
# You're missing this line below. Basic search for the confirmation.
# Note too that you will have to pass in the parameter `invite_token` for it to work
# I'm also assuming invite_token is unique among each invitation
confirmation = Invitation.where(invite_token: params[:invite_token])
# Notice that I'm first checking to see if the confirmation record exists, then doing an update
if confirmation and confirmation.update_attribute(:accepted, true)
flash[:success] = "Invitation confirmed!"
redirect_to 'static_pages/home'
else
flash[:notice] = "Failed :("
redirect_to 'static_pages/home'
end
end

How to handle active record find params[:id] in controller?

I'm wondering what is best practive for handling this type of situation in ruby on rails.
users_controller.rb
def show
#user = User.find params[:id]
end
If user is not found it throws an exception which isn't catched anywhere so it will display some ugly things to enduser.
Solution would be pack it into begin...rescue...end block:
def show
begin
#user = User.find params[:id]
rescue
flash[:error] = "User not found"
redirect :action => :index
end
end
although I've never seen such code in any rails article or tutorial I've seen.
What is the proper way of handling this type of situations?
See docs rescue_from
It depends on your requirement.
But you want a general solution then you can have a rescue block in ApplicaionController which will handle the RecordNotFound exception.
You can do
def show
#user = User.find_by_id(params[:id])
unless #user
flash[:error] = "User not found"
redirect :action => :index
end
end
But you cant expect you will call a link with id which is not in the db from within the application. Please see the answer of the question
The development environment will show you ugly error messages, but a production environment will just give an HTTP 404 error (page not found) when the id is invalid.
I think that you may be able to fix this with
#user = User.find(params[:id] = current_user)

uninitialized constant with rails friendships

I'm new to rails and getting the following error:
NameError in FriendshipsController#create
uninitialized constant FriendshipsController
this also shows up:
{"authenticity_token"=>"eQvv3flATE+P1TEErOWP/6fM8dEOIBxltobCxtM/F18=",
"friend_id"=>"32"}
When I click on the "Add Friend" Link on my users show page. I am following the railscast about self referential associations to a T, but I keep getting this error and I can't find any information about it, not even what "uninitialized constant" means. I've gathered from the internet that it MAY be related to the acts_as_authenticated plugin, but I followed the one fix I found and it didn't work.
Here is the code from my user/show.html.erb page:
<%= link_to "Add Friend", friendships_path(:friend_id => #user.id), :method => :post %>
and the code from my friendships controller:
def create
#friendship = current_user.friendships.build(:friend_id => params[:friend_id])
if #friendship.save
flash[:notice] = "Added friend."
redirect_to root_url
else
flash[:error] = "Unable to add friend."
redirect_to root_url
end
end
Where am I going wrong here. I haven't the faintest clue what is causing this. Please let me know if I am missing any needed code.
Difficult to tell. You should post the top part of your class... requires, class definition, includes, and anything else you have that is outside of your methods, as well as the create method.
Rails is complaining because you have used a constant before initializing it.
puts SomeConstant
# before
SomeConstant = 10
In this case the constant is a controller Class Name - FriendshipsController
Check if the class name is correct, i.e. you have a controller with that name in your app\controller directory.
I think you run
rails g controller Friendship
while you should have used
rails g controller Friendships
thats why all files are now singular
You can still go through and change all files though

Rails - Getting an error message from the model that is not a Validation error

So I have a method in a reservation model called add_equip. This method does some checking to make sure the added piece of equipment is valid (not conflicting with another reservation).
The checks work. If a added piece of equipment shouldn't be added it isn't, and if it should it is.
The problem is I can't figure out how to send the messages back up to the controller to be put in the flash message? I know I must be missing something here, but I've googled for a few hours now and can't really find any clear explanations how how to pass errors back up the the controller, unless they are validation errors.
add_equip in reservations_controller
def add_equip
#reservation = Reservation.find(params[:id])
#addedEquip = Equip.find(params[:equip_id])
respond_to do |format|
if #reservation.add_equip(#addedEquip)
flash[:notice] = "Equipment was added"
format.html { redirect_to(edit_reservation_path(#reservation)) }
else
flash[:notice] = #reservation.errors
format.html { redirect_to(edit_reservation_path(#reservation)) }
end
end
end
add_equip in reservation model
def add_equip equip
if self.reserved.find_by_equip_id(equip.id)
self.errors.add_to_base("Equipment Already Added")
return false
elsif !equip.is_available?(self.start, self.end)
self.errors.add_to_base("Equipment Already Reserved")
return false
else
r = Reserved.new
r.reservation = self
r.equip = equip
r.save
end
end
Any help would be greatly appreciated. I know I'm missing something basic here.
Using add_to_base to store the error message seems fine to me, you just need to figure out how to get it into the view.
How about:
flash[:notice] = #reservation.errors.full_messages.to_sentence
Assuming you're going to re-display a form, you could also probably use:
<%= f.error_messages %>
Or possibly:
<%= error_messages_for :reservation %>
Also, you might want to use flash[:error], then you can color it differently with a CSS class in your view.
I think I can see why errors are not being passed back to the user.
The problem is that you are sending a redirect to the user when the action fails instead of just doing a render, that means you lose any variables you set up to use within the request. Instead of adding errors to the flash, just render the edit page and set the flash to a normal message and everything should be fine.
For example:
def add_equip
#reservation = Reservation.find(params[:id])
#addedEquip = Equip.find(params[:equip_id])
respond_to do |format|
if #reservation.add_equip(#addedEquip)
flash[:notice] = "Equipment was added"
format.html { redirect_to(edit_reservation_path(#reservation)) }
else
flash[:error] = 'Error adding equipment'
format.html { render :action => :edit }
end
end
end
Now you can continue to use the normal form helpers for displaying error messages.
Also, just a little suggestion for the model code, try to use i18n when possible (including for flash messages in the controller). Although this is mostly a personal preference, it gives a logical home to all your messages and specific text, and alos allows you to create general or default messages which can be changed in one place instead of duplicating the change in multiple models and controllers.
eg.
def add_equip equip
if self.reserved.find_by_equip_id(equip.id)
self.errors.add_to_base(:already_added)
return false
elsif !equip.is_available?(self.start, self.end)
self.errors.add_to_base(:already_reserved)
return false
else
r = Reserved.new
r.reservation = self
r.equip = equip
r.save
end
end

Resources