Override default ActionMailer recipient at controller level - ruby-on-rails-4

For demonstration purposes, I would like to override the Rails 4 ActionMailer recipient at controller level.
The following initializer does what I want, but when I want to change mail.to address, I need to recommit my code and restart the server.
# config/initializers/override_mail_recipient.rb
if Rails.env.production?
class OverrideMailRecipient
def self.delivering_email(mail)
mail.to = 'example#domain.com'
end
end
ActionMailer::Base.register_interceptor(OverrideMailRecipient)
end
What I would want is to be able to access a link like:
get '/default_mail_recipient/:email' => 'controller#default_mail_recipient', as: :mail_recipient
And then in a controller:
def default_mail_recipient
ActionMailer::Base.override_recipient = params[:email]
redirect_to :root, :notice => "Default mail recipient overridden"
end
I doubt that this will be possible, but maybe there's a Rails ninja out there that might help me or point me in another direction.

Related

Redirecting a request in a routing constraint

I have Sidekiq mounted in my routes file to the /sidekiq endpoint.
I use a constraints option to have it call an external class for validation as a way of preventing non-privelaged users from accessing that endpoint.
# config/routes.rb
mount Sidekiq::Web => "/sidekiq", constraints: Sidekiq::AdminConstraint.new
# lib/sidekiq/admin_constraint.rb
module Sidekiq
class AdminConstraint
def matches?(request)
return false unless request.session[:user_id]
user = User.find_by_id(request.session[:user_id])
user && Ability.new(user).can?(:manage, :sidekiq)
end
end
end
This setup works great. However, it only lets me return true / false on whether the request should go through or not. It does not let me -
Set a flash message (e.g. "You are not permitted to access that page") and
Redirect to some arbitrary page
In that sense, I'm looking for it to behave more like a controller's before_filter.
Is there a way I can modify the request object that's passed in to implement that redirect?
Thanks!
I don't have idea directly set the flash messages, But we can use in different way.
Use the following solution
In your routes.rb, add the following line in the end of the file
match "*path", :to => "application#error_404"
This basically means, any path that is not defined in your route will end up going to error_404 in application_controller. Its very important to put this at the end of your file
And in your ApplicationController, add
def error_404
redirect_to root_path
end
Thanks

Ruby on Rails Pundit's current_user is nil in integration test

I'm using the gems pundit and devise. I have a delete link that only shows up if you are an admin. I have an integration test that I would like to verify that the delete link only shows up for admins.
test 'comment delete link shows when it should' do
log_in_as #admin
get movie_path(#movie)
assert_select 'a[href=?]', movie_comment_path(comments(:one), #movie.id)
end
My test_helper.rb looks like this:
...
class ActiveSupport::TestCase
...
def log_in_as(user, options = {})
password = options[:password] || 'password'
if integration_test?
post user_session_path, 'user[email]' => user.email, 'user[password]' => user.password
else
Devise::TestHelpers.sign_in user
end
end
private
# Returns true inside an integration test.
def integration_test?
defined?(post_via_redirect)
end
end
The response.body looks all right, but indeed there is no delete link. There is one when I run the development server and visit the page myself. I've narrowed this down to the current_user that pundit uses in the policies is being passed in with a value of nil. This is my comment_policy.rb:
class CommentPolicy
attr_reader :current_user, :comment
def initialize(current_user, model)
#current_user = current_user
#comment = model
end
def create?
if #current_user
#current_user.member? or #current_user.content_creator? or #current_user.moderator? or #current_user.admin?
end
end
def destroy?
if #current_user
#current_user == #comment.user or #current_user.moderator? or #current_user.admin?
end
end
end
As a closing remark, I've heard that Rails 5 has opted for integration tests instead of controller tests as we know them from Rails 4 for the default type of tests to be generated for our controllers. If this is the case, devise would be a heck of a lot more useful out of the box when using Rails 5 if the sign_in/sign_out helpers that work in controller tests were made to work in integration tests as well. But would I still have this issue of pundit not knowing what current_user is? I'm assuming this all works fine in controller tests because the current_user is scoped to controllers? Any and all light shed on this topic is much appreciated, but I would really like to figure out how to get integration tests to work with this setup because I have about a billion I want to write right now.
Not that it totally matters, but does it need to be using current_user in the policy or can it just use user in the policy. By this I mean according to the elabs/pundit README on Github I would just use #user and user everywhere instead of current_user. Read the README if I confused you.
Additionally the nil for current_user typically occurs when you don't have a valid CSRF token for your request. When you do this on the website manually by going to localhost:3000 or w/e you are first performing a get on the login path before doing the post on the login path with your credentials. In your integration test I don't seem to see where you are performing that get in order to get the CSRF for your session.
Hope this helps!!!

devise_inviteable - issue with GET users/invitation/accept?invitation_token=xxxx re-directed to sign_up

ruby '2.1.2'
rails (4.1.4)
devise (3.2.4)
devise_invitable (1.3.6)
routes.rb
devise_for :users, :controllers => { invitations: 'users/invitations' }
users/invitations_controller.rb
class Users::InvitationsController < Devise::InvitationsController
prepend_before_filter :require_no_authentication, :only => [:edit, :update, :destroy]
# i dont need to override anything
end
rake routes
accept_user_invitation GET /users/invitation/accept(.:format) users/invitations#edit
remove_user_invitation GET /users/invitation/remove(.:format) users/invitations#destroy
user_invitation POST /users/invitation(.:format) users/invitations#create
new_user_invitation GET /users/invitation/new(.:format) users/invitations#new
PATCH /users/invitation(.:format) users/invitations#update
PUT /users/invitation(.:format) users/invitations#update
every part of the application needs to be authenticated - except the accept_user_invitation path
my application controller does have:
class ApplicationController < ActionController::Base
before_action :authenticate_user!
end
Not sure why this is not working - anyone care to help me understand what I am doing incorrectly ? Every time I go to the URL I am redirected to signup
Thanks in advance. I am almost ready to roll my own !
I figured out why devise_invitable was re-directing and that was because the invitation_token was incorrect.
When overriding the default behaviour to send your own email
user = User.invite!(params) do |u|
u.skip_invitation = true
u.invitation_sent_at = Time.now
u.invited_by_id = 1
u.invited_by_type = 'User'
end
Looking at the code:
https://github.com/scambra/devise_invitable/blob/master/lib/devise_invitable/model.rb#L200
There is a temporary raw_invitation_token which is the actual token needed for your url and invitation_token which is encrypted. I have to admit there was some confusion here!
In your url generation the token you must use is raw_invitation_token as devise_invitable will decrypt this token: https://github.com/scambra/devise_invitable/blob/master/lib/devise_invitable/model.rb#L277
When I send the email or generate the link this works:
# use the raw_invitation_token rather than invition_token
# when generating your links for the mailer
token = user.raw_invitation_token
puts "#{accept_user_invitation_url(::ActionMailer::Base.default_url_options.merge({:invitation_token => token})) }"
Use the user.raw_invitation_token for your urls and the process works as intended
I have requested that the documents be improved and added a pull request - hope this helps someone

Rails 4:register a person in my rails app through voice call verification

Can you please share that how can i make a outbound call to a person who want to register in my Rails 4 application and make a verification through his voice(in short i want to register a person in my rails app through voice call verification), Is that possible with twillo or suggest some other way to do it?
Please suggest the step by step or suggest some tutorial/doc/video
https://github.com/twilio/twilio-ruby
and
https://www.twilio.com/docs/quickstart/ruby/twiml
Call and ask for verification:
require 'twilio-ruby'
# build up a response
response = Twilio::TwiML::Response.new do |r|
r.Say 'hello there, enter verification code', :voice => 'alice'
r.Dial :callerId => '+14159992222' do |d|
r.Gather :numDigits => '5', :action => "/verify_code?id=#{id}", :method => 'get' do |g|
g.Say 'Verified thankyou.' if verified?
else
# hangup or set behaviour
end
end
end
end
def verify_code
#verification = Verification.where(verification_code: params[:id]).first
if #verification
#activate
else
# Handle errors
end
end
Finally in your model you'll need code that generates the verification code, and verifies if it is confirmed
class Verification < ActiveRecord::Base
before_create -> { self[:verification_code] = rand.to_s[2..5] }
end

Generating a unique URL with tokens in Rails 4 for an external form response

I have a 'Feedback' model whereby a user should be able to request feedback on his/her job performance. I have written basic actions for creating a new feedback request, and the mailer for sending the request to the provider (person who will respond with feedback).
I would like advice from the community on implementing the following:
Once a new feedback request is created, the email that is sent should contain a link to a form where the provider can input his feedback on the users performance.
The feedback provider should not be required to log-in or sign-up in any way (i.e. completely external to the application).
Once submitted, feedback from the provider should be captured in the
system.
Now, I have the following ideas to implement it, but am not sure if this is the best way to proceed:
Generate a unique token upon the creation of a new feedback request. Something like this: Best way to create unique token in Rails?.
The token should then be entered into 'feedbacks' table.
Mailer should then generate variable (e.g. #url) which generates link to another controller (let's say 'external_feedback' and action which does not require log-in (e.g. no before_filter :authenticate_user! from Devise).
That URL should contain a parameter with the token for the specific feedback request.
The action should be to update the 'feedback' request and a form generated with simple_form.
The whole thing is similar to responding to a questionnaire or survey (like Survey Monkey).
After some research I believe the Friendly ID gem may be useful here. I was also reading Section 8 of http://guides.rubyonrails.org/form_helpers.html and perhaps I need to implement an authenticity_token in the formal sense. What I am really looking for is:
Is the above approach the generally correct way to go about doing this?
If so, any specifics on how you would implement it (with or without Friendly ID)?
Do you know of any gems that exist for generating such URLs/tokens?
Thank you in advance. I am now including the current state of model and controller details:
feedback.rb
# == Schema Information
#
# Table name: feedbacks
#
# id :integer not null, primary key
# user_id :integer
# p_first_name :string(255)
# p_last_name :string(255)
# p_email :string(255)
# goal_id :integer
# u_comment :text
# p_comment :text
# created_at :datetime
# updated_at :datetime
#
class Feedback < ActiveRecord::Base
belongs_to :user
belongs_to :goal
has_many :feedback_attributes
validates_presence_of :p_first_name, :p_last_name, :p_email, :goal_id
end
And this is my mailer:
class FeedbackMailer < ActionMailer::Base
def feedback_request(user, feedback)
#user = user
#feedback = feedback
#url = 'http://thisistheexampleurlforfeedback'
mail(to: #feedback.p_email, subject: "#{#user.first_name} #{#user.last_name} has requested your feedback", from: #user.email)
end
end
Add a token field to the feedback model with an index and add a callback to populate it on create e.g.
feedback.rb
before_create :add_token
private
def add_token
begin
self.token = SecureRandom.hex[0,10].upcase
end while self.class.exists?(token: token)
end
now add a new route for the providers feedback
resources :feedbacks do
get 'provider'
put 'provider_update' # you might not need this one, if you are happy to use update
end
In your controller make sure they don't get rejected by devise
before_filter :authenticate_user!, except: [:provider, :provider_update]
...
def provider
#feedback = Feedback.find_by token: params[:token]
end
then in the app/views/feedback/provider.html.haml you can use url in simple_form to send it to the correct update location and only provide the input that they should see.
f.inputs :p_comment
Now update your mailer.
#url = provider_feedback_url(#feedback, token: #feedback.token)
You could do something similar to this using friendly id but you would still need to create some sort of unique slug and then use Feedback.friendly.find instead. I think you would want to combine it with a token to ensure it's still the provider giving the feedback - so the only benefit would really be hiding the true id/count. I think you should update p_* fields to provider_* so that the next dev knows what's in it - it's not the 90s!