controller action contains more than one model method call? - ruby-on-rails

I have a simple update action in a Rails 4 controller:
#more stuff here
def update
if #user.update(user_params)
flash[:notice] = "User #{#user.username} updated"
redirect_to users_path
else
render 'edit'
end
end
private
def set_user
#user = User.find(params[:id])
end
However, RubyMine is warning about #user.update and #user.username:
This inspection warns if a controller action contains more than one model method call, after the initial .find or .new. It’s recommended that you implement all business logic inside the model class, and use a single method to access it.
I don't see more than one model method call here. Can some one explain what is going on?
EDIT - I have something similar in the create action without warns, so I believe there is something to do with user_params...
def create
if #user.save
flash[:notice] = "User #{#user.username} created"
redirect_to users_path
else
render 'new'
end
end

Assuming username is a method in model where you merge user first_name and last_name.
I guess #user.update(user_params) and #user.username are your both method calls. One that saves the model, another that sets the user full name in flash notice.
It's just a warning from rubymine that just recommends you some actions to do, not necessary to follow them.

Related

ruby on rails undefined method 'valid' when using update

I am using the same commands that I previously used in successful projects but now I suddenly can't validate any updates to the object(in this case, User). Everything else works fine but any attempt to check my validations for an update results in this error-
'undefined method `valid?' for # '
It is finding successfully finding the user and if I skip the .valid? statement then it will update, just without checking any of my model validations. I recently switched from SQLite to PostgreSQL, I am not sure if that's giving me the problem. I am new to Ruby but I couldn't find anything on this specific problem.
Please let me know if I should include the entirety of my controller or any of my model but as my create works fine, I feel like all the relative code is just in this little section-
class UsersController < ApplicationController
def update
#user = User.find(params[:id])
puts "#Is this working???!! #{#user}" ///prints #Is this working???!! #<User:0x00000001f24468>
#user = User.update(user_params)
if #user.valid?
redirect_to "/users/#{#user.id}"
else
flash[:errors] = #user.errors.full_messages
redirect_to "/users/#{#user.id}/edit"
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password)
end
Your problem is here:
#user = User.update(user_params)
If you put in your check after, you would see: #Is this working???!! true, which would ironically enough inform you that it's not working.
That's because User.update(user_params) returns true or false depending on whether it is successful or not. This means your #user object is now simply either true or false, which you can't call valid on.
If you want to handle successfully updating / failing to do so, try:
def update
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to "/users/#{#user.id}"
else
flash[:errors] = #user.errors.full_messages
redirect_to "/users/#{#user.id}/edit"
end
end
ActiveRecord update(id, attributes)
Updates an object (or multiple objects) and saves it to the database, if validations pass. The resulting object is returned whether the object was saved successfully to the database or not.
Then, you can do this checking if #user.update(user_params)
def update
#user = User.find(params[:id]) //Find user
if #user.update(user_params) // Update user if validations pass
redirect_to "/users/#{#user.id}"
else
flash[:errors] = #user.errors.full_messages
redirect_to "/users/#{#user.id}/edit"
end
end
Or, you can call the update method directly in your model class, but the first argument must be the user ID
User.update(params[:id], user_params)
Thank you both for your quick answers. I was replying to tell you that I already tried that and it worked but did not validate. But as two of you told me the same thing, I decided to test it out again and the validations did indeed work this time so thank you (although I definitely have a user with an email of 'asdf' from last time).
Intestering enough, I found another answer although I have no idea why it worked. I added another puts statement after the update and realized my object had been converted to an array so I came up with this other (worse) alternative answer-
def update
#user = User.find(params[:id])
puts "#Is this working???!! #{#user}"
#user = User.update(user_params)
puts "#Is this working???!! #{#user}" ///prints #Is this working???!! [#<User id: 2, name: "James Dean", etc..>]
if #user[0].valid?
redirect_to "/users/#{#user[0].id}"
else
flash[:errors] = #user[0].errors.full_messages
redirect_to "/users/#{#user[0].id}/edit"
end
end

Can't overwrite the active admin default redirect path

I am using active admin in my application. In my controller, I have an action update with redirect_to function. But while updating, it threw me an error.
Render and/or redirect were called multiple times in this action. Please note that you may only call render or redirect, and at most once per action. Also note that neither redirect nor render terminates execution of the action, so if you want to exit an action after redirecting, you need to do something like redirect_to(...) and return.
def update
#user = User.find(params[:id])
#user.update
mailers.notify(#user).deliver
redirect_to user_path(#user)
end
I tried
only redirect_to
redirect_to() and return
but nothing works.
before_filter :only =>[:create,:update] do
if self.action_name.to_sym == :create
#user = User.new(params[:user])
else
#user = User.find(params[:id])
end
I fix it by adding this to my update action .This works for me fine.
def update
update!do |format|
format.html { redirect_to_user_path(#user)}
end
What is your purpose? Why you use mailers.notify(#user).deliver inside the update action?
Move the notification to after_update filter in your User model, smth like this:
after_update :send_notifications
def send_notifications
Mailer.notify(self).deliver
end
Change the update method to smth like this:
def update
super do |format|
redirect_to user_path(#user), notice: "Your notice message" and return if resource.valid?
end
end

Stop deletion of admin where name like 'string_name'

I'm trying to stop A particular Admin from being removed from the database with ruby on rails
I have tried a few things but heres the code as it stands
Edit 2 changed User.name to #user.name
Model
after_destroy :can_not_destroy_super_admin
private
def can_not_destroy_super_admin
if #user.name == "super admin"
raise "Can't delete this admin"
end
end
I think its a problem with User.name, but I know its seeing this code because I've had errors raising issues with different code I've tried in here.
I'm aware that this is a relatively crude method for stopping deletion of an admin but it's a simple way of getting what I need done.
Any suggestions or help is very much appreciated.
Edit.1
Here is the destroy method
Controller
def destroy
#user = User.find(params[:id])
begin
#user.destroy
flash[:notice] = "User #{#user.name} deleted"
rescue Exception => e
flash[:notice] = e.message
end
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
I'm guessing your destroy action looks something like this?
def destroy
#user = user.find params[:id]
#user.destroy
end
If this is the case, the user you want to check against in your callback is #user.name, not User.name. You want to ensure that the actual user instance you called destroy on is the same one you're checking the name of.
Edit: As determined in the comments, the callback is actually on the model, I misinterpreted as being in the controller. In the model, to reference the objects name, only name is needed, not User.name or #user.name.

Rails - How does ActiveRecord's save method work?

A newbie question regarding the ActiveRecord's save method.
If i have this code (as in rails guide):
def create
#post = Post.new(params[:post])
if #post.save
redirect_to #post
else
.....
end
end
The save method returns the new created Post object? How, after the code #post.save, rails know how to substitute the redirect_to #post with the proper post_id (1 or 2 or 3 or ....) to build the link?
It's an OOP concept.
So, after create, the #post is updated with the id, and everything just works.
Take a look at this code.
Hope it helps.
I'm going to explain it by presenting another piece of code that should make things easy to understand
def create
#user = User.new(params[:user])
if #user.save
redirect_to #user
Now :user contains the following information based on the User model: id, name, email, telephone.
So that means we have actually assigned to #user the above hashes.
The redirect_to will retrieve the hashes that is already stored in #user and display the new profile page.
I hope it helped.

Rails: attributes not being saved even though I called #user.save

I'm running this function, and I KNOW that it gets called because the redirect_to is working. But for some reason, #user isn't! If it helps, #user is devise based.
def make_feed_preference
#user = current_user
##user.feed_preference = params[:preference]
#user.feed_preference = "time"
#user.name = "Shoo Nabarrr"
#user.karma = 666
#user.save
redirect_to '/posts'
end
I fixed it myself. I had to create a new class attached to users in order to get it to work. Lol.
Do you have any validations on this user? They are probably blocking this save. The redirect_to will be called regardless of whether or not the save passes or fails.
I would recommend doing it like this instead:
if #user.save
redirect_to '/posts'
else
render :feed_preference
end
Where :feed_preference is the form where users enter their feed preferences.
There are cases where I want to be sure to update a flag or other field on a record even if the record has validation problems. (However, I would never do that with unvalidated user input.) You can do that thusly:
def make_feed_preference
case params[:preference]
when 'time', 'trending_value', 'followers'
current_user.update_attribute 'feed_preference', params[:preference]
flash[:notice] = 'Your feed preference has been updated.'
else
flash[:notice] = 'Unknown feed preference.'
end
redirect_to '/posts'
end

Resources