Render email text conditionally based on who sent it - ruby-on-rails

Users can accept a project, or an admin user can do it on their behalf. Regardless of the sender, an email is sent. I would like the contents of the email to be different when an admin triggers its' sending.
There's a current_user method in ApplicationController. When current_user.admin? evaluates to true, I'd like to do something else.
How can I access current_user from either inside the mailer's view template or from the *_mailer.rb itself?
I'm also open to working with controller/action names. For example, if controller_name == "Admin". It'll get us there, but this method is unavailable in the mailer as well.

Just pass the current_user to the mailer when you are creating a new delivery:
YourMailer.conditional_creation_email(current_user).deliver_now
In your_mailer.rb
def conditional_creation_email(sender)
if sender.admin?
# do...
mail(to: '#gmail.com', subject: 'New Order')
end
end

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.

How to pass information from one controller to another via view rails

I am working on a reservation project and after login I want to pass the current user information from the Sessions Controller to a Reservations Controller via a home page. How can I do that? I have been following Michael Hartl's Rails Tutorial for the login. Here's what I have tried in the create section of the Sessions Controller
render home_path :local_variables[:id => user_id]
and in the home_path(users#home)
<%= link_to new_reservation_path(:user_id => :id) %>
but it shows me an undefined method error. My Reservation model has a user_id column.I am confused regarding this matter. What should I do?
render home_path :local_variables[:id => user_id]
Seems weird to me to pass locals that way (don't even know if it's possible, never seen locals used outside of rendering views/partials).
I think the best way is to redirect instead and set the user in the sessions once they have been logged in successfully, so in your login action:
user = User.find_by_email(params[:user][:email]) # or however you are finding the person trying to login
session[:user] = user
redirect_to home_path
then in users#home
#user = session[:user]
and finally, in the view:
<%= link_to new_reservation_path(:user_id => #user.id) %>
EDIT
Actually, probably not a good idea to store an object in the session, instead of
session[:user] = user
You could try:
session[:user_id] = user.id
and then to find the user:
#user = User.find(session[:user_id])
If you still get an undefined error then it's probably because the user is nil (unless the User model actually has no id attribute, which would be strange) so there might be an issue with the login part, it's hard to say without knowing what that looks like.
If you need the logged in user on every page, you could abstract the functionality out into the application controller:
before_filter :check_user
def check_user
#user = User.find(session[:user_id]) if session[:user_id]
end
Then, you can use the #user instance variable anywhere in your app.

Rails devise set flash message from another action

I'm trying to show devise error message from another action. I have Registrations Controller with subscription action.
I would like to show error message from my subscription action when the user has already signed up. So this is kind a update of existing user, but without password, just validation for attributes.
If validation fails devise shows error message via subscription action.
By default when the user get updated error message is rendered via update action.
I assume I need to reuse the code from Registrations Controller update action and apply this code to my subscription action, but no luck. Can anyone help to make to show error message from subscription action?
here devise registrations controller
Ideally, you should create a separate controller SubscriptionController which contains new and create (RESTful actions?) which enable you to display a form where you accept the user details and process it, respectively.
Here, in the SubscriptionController's create action, you can append errors to the flash hash provided by the ActionController.
class SubscriptionController < ActionController
def create
flash[:success] = 'User Registered Successfully'
end
end
In your view(layout), you can have something like this:
<% flash.each do |name, msg| %>
<div class="flash">
<%= msg %>
</div>
<% end %>
which will allow you to display the flash message.

Sign out redirect path for devise

I have overriden Devise's sign out path and made it request.referer. The problem with that is if the user is on a page which has the authenticate_user! before filter applied, I am sent to the sign in page and shown an error. This is not ideal, and I would like to redirect to the root_path ONLY when the user is coming from a path which has authentication requirements. What is the best way to do this?
I ended up inspecting the callbacks for the controller that the referrer url is associated with. If there are any authenticate_*! callbacks, they are each inspected to see if there are any actions specified in the #if instance variable. If there are none, the callback is applied to all of the actions and we know that the referring url is from a restricted action. If there are actions specified, we use regex to check if the referring action is restricted or not.
Any of the callbacks which meet the criteria are added to an array. After looping through the callbacks, we check if that array is empty. If it is, we send the user back to request.referer. If it is not empty, that means that sending them to request.referer will redirect them to the sign in page and show an error. In that case, we send the user to root_path.
If anything raises an error, the user is sent to root_path.
Here is the code:
def after_sign_out_path_for(resource_or_scope)
begin
controller_name = Rails.application.routes.recognize_path(request.referer)[:controller]
controller_class = "#{controller_name}_controller".camelize.constantize
authentication_callbacks = controller_class._process_action_callbacks.select { |callback| callback.filter.match /authenticate_\w+!/ }
action_name = Rails.application.routes.recognize_path(request.referer)[:action]
restricting_callbacks = []
authentication_callbacks.each do |callback|
callback_scope = callback.instance_variable_get(:#if)
if callback_scope.empty? || callback_scope.first.match(/action_name\s==\s(\'|\")#{Regexp.quote(action_name)}(\'|\")/)
restricting_callbacks << callback
end
end
restricting_callbacks.empty? ? request.referer : root_path
rescue Exception => e
request.referer
end
end

Devise Mailer, using custom email template for existing module

I'm using ruby on rails, with devise.
I have a senario wherin an Administrator would be able to add new user to the web application giving his email id and under this senario i'd be creating a new user. and would like to issue an Auth-Token to the user email. so when he clicks the link in his email, he'd be prompted to issue his/her new password.
My forgot password implementation.
def create
resource = User.send_reset_password_instructions(params[:user])
if successfully_sent?(resource)
render json: {status: :true},status: 200
else
render json: {status: :false, error: user.errors.full_messages.join(",") } , status: 200
end
end
Now my question is how do i use the same logic as that of forgot password, but use different Email-template for the user-added by the administrator screen. ?
Thanks a lot.
Why are you redirecting a user to forgot your password page when you can simply redirect him/her to settings page from where a user can change his/her password?
Create a mailer action with its template and simply call that mailer action inside the method where your admin is creating users. e.g:
if your mailer action is:
def forgot_pass(email)
mail(to: email, subject: 'Change your pass')
end
and your method where your admin is creating users is:
def create_user
# your logic
YourMailerClass.forgot_pass(xyz#abc.com).deliver
end
For more details on mailer refer to here

Resources