Conditional value for ActiveRecord create method only - ruby-on-rails

I have a form where I have an administrator creating new users. The form uses the User model I created (login, password, first_name, etc...). For the last field on the form, I want to have a checkbox that doesn't need to be stored as part of the User record, but it is needed for the controller. This will control if the newly created user will receive a welcome email or not. This is in Rails 3.0.3.
def create
#user = User.new(params[:user])
if #user.save
if #user.send_welcome_email
UserMailer.welcome_email(#user).deliver
end
redirect_to(admin_users_url, :notice => "User #{#user.name} was successfully created.")
else
render :action => "new"
end
end
In my view (haml) I am trying to access it like this:
%p
Send Welcome Email?
= f.check_box :send_welcome_email
I tried to make this an attr_accessible: :send_welcome_email but the controller does not recognize it. I get an
undefined method 'send_welcome_email' for #<User:0x00000100d080a8>;
I would like it to look like this:
What is the best way to get this working?

What you want is not attr_accessible, but attr_accessor. That's it.
However, your code will look nicer if you move the email sending code to an observer.

Since you're not saving it on the user, you can use check_box_tag instead of f.check_box and access it with params[:send_welcome_email]. Although even the way you have it, I think you could access it as params[:user][:send_welcome_email].

As an alternative to attr_accessor, you can always remove it from the parameters first:
def create
send_welcome_email = params[:user].delete(:send_welcome_email)
#user = User.new(params[:user])
if #user.save
UserMailer.welcome_email(#user).deliver if send_welcome_email
redirect_to(admin_users_url, :notice => "User #{#user.name} was successfully created.")
else
render :action => "new"
end
end
You may have to make sure that the parameter is successfully transformed into a boolean; otherwise the condition will always be true (0 is true in Ruby).

Related

How to look check whether model exists and create if it doesn't with a single form?

I'm trying to implement a form with the following behavior:
1) Input some semantic data about a user (i.e. username).
2) Do a User.find_by(:username = username).
3) If such a user exists, direct to show page for that user.
4) If such a user does not exist, create a new user with the provided username, then redirect to the show page for that user.
This should be simple but I cannot figure out how to format the form_for helper and my show and create actions in my user_controller to implement this behavior.
I currently have:
form_with :url => 'users/:id', :method => :get do
...
end
because I'm ultimately trying to invoke the "show" method of the controller. However, my form does not take in a user's id as a parameter, and when the user does not yet exist there is no :id parameter to access at the time of the form's submission.
How can I set up my form to redirect to show in each case, while still adhering to the logic explained above?
You can do something like this in your User's Controller create action
def create
usr_name = params[:username]
#user = User.where(username: usr_name).first_or_initialize
if #user.persisted?
redirect_to user_path(#user) # or whatever your user show path is
elsif #user.save
redirect_to user_path(#user)
else
render :new
end
end
You would just need to make sure that you are validating the uniqueness of usernames.
Also, first_or_initialize(and its counterpart first_or_create) can take in a block. So, you can assign other attributes to the new User like this...
User.where(username: usr_name).first_or_initialize do |usr|
usr.some_attribute = some_value
end
you can use find_or_initialize_by(unique_key) in your create method.unique_key can be any key which you are using to identify your user such as email,phone etc.

Get any id to any user exists in the database

I am new to rails and have a task that asks me to send an invitation for any user to be admin in my magazine here is my piece of code
def invite
inviteUser = { 'user_id' => current_user.id, 'Magazine_id' => params[:id] }
CollaborationInvitation.create(inviteUser)
#magazine = Magazine.find(params[:id])
redirect_to :back
rescue ActionController::RedirectBackError
redirect_to root_path
end
I need to replace current_user.id with something that refers to any user's id which exists in my database to send him an invitation to be admin with me I tried to add #User=Users.All and then pass it as a variable but it got me an error I tried a lot of things but every time I get an error except for adding current_user.id
ps: I am using devise for authentication
You asked a couple things, and it is kind of confusing what you want to do.
Here is how you get all ids of records in a model.
Rails4: User.ids
Rails3: User.all.map(&:id)
Or (not sure if #pluck is in Rails 3 or not)
User.pluck(:id)
If you want to get a random user (you mentioned "any user") you could do.
User.find(User.pluck(:id).sample)
Though I think what you really want to do is to pass the id or some other attribute of a user as a param to the action and send that user an invitation.
Presumably you either have a post or get route for "users#invite" (the action you wrote in your question). You can add a named parameter there or you can pass a url param or if you are using a post route, you could add the param to the post body.
Then in your contoller you can do something like this (I'll use email as an attribute):
def invite
#user = User.find_by(email: params[:user_email])
#Rails 3 like this
# #user = User.find_by_email(params[:user_email])
# now do stuff with user
end
User.all will return you the collection of users. So,
Find the user object to get an id...
Try this code....
def invite
inviteUser = { 'user_id' => User.find_by_email('user#example.com').id, 'Magazine_id' => params[:id] }
CollaborationInvitation.create(inviteUser)
#magazine = Magazine.find(params[:id])
redirect_to :back
rescue ActionController::RedirectBackError
redirect_to root_path
end
You can try
User.last.id
or
User.find_by_email("xyz#test.com").id
or
User.where(email: "xyz#test.com").first.id
Replace xyz#test.com with desired user email address. To get more details on rails active record query interface, please read rails guides http://guides.rubyonrails.org/active_record_querying.html

Is there a way to get the visitors city and country in Rails controller?

In my current app, i use Geocoder gem to get the city and the country of the visitor. I use hidden fields in my view to get these details. When the login form is submitted, these details will be sent to the controller and the controller will save them to the database. When I try to get these details directly from the controller by using
request.location.city
It will assigning a blank value to the database. If I use hidden fields in the view, some one can temper with them right? So, how can I fix this?
You should store visitor information before you render any content:
class UsersController
def new
# I suspect that, for fast insert, you should probably use a NoSQL database
# to perform `store!` or even just write it to a log file
Visitor.store!(:city => request.location.city, :ip => request.ip)
end
def create
#user = User.build(params[:user].merge(:city => request.location.city))
if #user.valid?
#user.save
flash[:notice] = "You've been registered!"
redirect_to user_dashboard_path
else
flash[:notice] = "Couldn't register your account"
render action: "new"
end
end
end

Rails - passing parameters in a redirect_to - is session the only way?

I have a controller set as the root of my app. It accepts in a parameter called uid and checks to see if the user exists. If not, I want it to redirect to the new user page and pre-populate the uid field with the uid in the parameter.
In my root_controller:
def index
if params[:uid]
#user = User.find_by_uid(params[:uid])
if (!#user.blank?)
# do some stuff
else
session[:user_id] = params[:uid]
redirect_to(new_user_path, :notice => 'Please register as a new user')
end
else
# error handling
end
end
In my users_controller, GET /users/new action:
def new
#user = User.new
#user.uid = session[:user_id]
# standard respond_to stuff here
end
This all works fine, but is this an acceptable way to do this? I originally tried passing the uid in the redirect statement, like:
redirect_to(new_user_path, :notice => 'Please register as a new user', :uid => params[:uid])
or even testing it with:
redirect_to(new_user_path, :notice => 'Please register as a new user', :uid => 'ABCD')
but neither seemed to pass the value to users_controller...I couldn't access it using params[:uid] from that controller.
Is session a proper place to store stuff like this, or is there a better way to pass it via the redirect? Thanks!
A session is fine to store that kind of information. Depending on what you are doing with the uid it might actually be dangerous to allow it to be read from the URL. Imagine if the end user was malicious and started putting other user's IDs into there.
For messages that should only last until the next request Rails actually has the flash object which will carry it over for you.
http://guides.rubyonrails.org/action_controller_overview.html#the-flash
That said, if you want to redirect to a url and pass some params, do so like this:
redirect_to(new_user_path(:notice => 'Please register as a new user', :uid => 'ABCD'))
The params you want to pass are arguments to the new_user_path method, not the redirect_to method.

Force validation of blank passwords in Authlogic

I'm adding a password reset feature to my Rails application that uses Authlogic. I was following the guide here: http://www.binarylogic.com/2008/11/16/tutorial-reset-passwords-with-authlogic/ and everything works as I'd like except for one thing: the password reset form accepts blank passwords and simply doesn't change them.
I've been searching around, and have learned that this is the intended default behavior because it allows you to make user edit forms that only change the user's password if they enter a new one, and ignore it otherwise. But in this case, I specifically want to enforce validation of the password like when a user initially registers. I've found two possible solutions for this problem but haven't been able to figure out how to implement either of them.
1) Someone asked this same question on Google Groups:
User model saves with blank password
Ben's response was to use #user.validate_password = true to force validation of the password. I tried this but I get an undefined method error: undefined method 'validate_password_field=' for #<User>.
2) There seems to be an Authlogic configuration option called ignore_blank_passwords. It is documented here:
Module: Authlogic::ActsAsAuthentic::Password::Config#ignore_blank_passwords
This looks like it would work, but my understanding is that this is a global configuration option that you use in your initial acts_as_authentic call in the User model, and I don't want to change it application-wide, as I do have a regular edit form for users where I want blank passwords to be ignored by default.
Anyone found a solution to this? I see validate_password= in the change log for Authlogic 1.4.1 and nothing about it having been removed since then. Am I simply using it incorrectly? Is there a way to use ignore_blank_passwords on a per-request basis?
This is kind of an old thread, but since it is unanswered I'll post this.
I've managed to do it a bit more cleanly than the other solutions, "helping" authlogic validations with my own.
I added this to user:
class User < ActiveRecord::Base
...
attr_writer :password_required
validates_presence_of :password, :if => :password_required?
def password_required?
#password_required
end
...
end
You can reduce it to two lines by making an attr_accessor and using :if => :password_required (no interrogation), but I prefer this other syntax with the interrogation sign.
Then your controller action can be done like this:
def update
#user.password = params[:user][:password]
#user.password_confirmation = params[:user][: password_confirmation]
#user.password_required = true
if #user.save
flash[:notice] = "Password successfully updated"
redirect_to account_url
else
render :action => :edit
end
end
This will have a local effect; the rest of the application will not be affected (unless password_required is set to true in other places, that is).
I hope it helps.
This what I did.
class User < ActiveRecord::Base
attr_accessor :ignore_blank_passwords
# object level attribute overrides the config level
# attribute
def ignore_blank_passwords?
ignore_blank_passwords.nil? ? super : (ignore_blank_passwords == true)
end
end
Now in your controller, set the ignore_blank_passwords attribute to false.
user.ignore_blank_passwords = false
Here, you are working within the confines of AuthLogic. You don't have to change the validation logic.
User.ignore_blank_passwords = false
Use model, not object for setting this property.
def update_passwords
User.ignore_blank_passwords = false
if #user.update_attributes(params[:user])
...
end
User.ignore_blank_passwords = true
end
Maybe test the value of the parameter in the controller? (air code):
def update
#user.password = params[:user][:password]
#user.password_confirmation = params[:user][: password_confirmation]
if #user.password.blank?
flash[:error] = "Password cannot be blank"
render :action => :edit
return
end
if #user.save
flash[:notice] = "Password successfully updated"
redirect_to account_url
else
render :action => :edit
end
end
Apart from zetetic's solution you could do it this way:
def update
#user.password = params[:user][:password]
#user.password_confirmation = params[:user][: password_confirmation]
if #user.changed? && #user.save
flash[:notice] = "Password successfully updated"
redirect_to account_url
else
render :action => :edit
end
end
You're basically checking if authlogic changed the user record (which it doesn't if the password is empty). In the else block you can check if the password was blank and add an appropriate error message to the user record or display a flash message.

Resources