Rails: Flash messages doesn't clear until it is read/accessed - ruby

I set the flash message as below in one of my routes
def signup
flash[:is_signup] = true
... redirect_to route1 : route2 // based on some logic, redirect accordingly
end
def route1
// access flash[:is_signup]
flash.discard(:is_signup)
// do something
end
As depicted above, after i set the flash variable, i could redirect_to either the route(route1) that uses this flash variable or another route(route2) that doesn't care about this flash variable at all.
The issue is, when i redirect to route2, and then go on and mind my own business, hitting several routes/actions in the process, when i end up hitting the route1, the flash variable is still there.
I haven't seen anything in the documentation that says it is available until it is read. Is this the case? or am i doing something wrong?
Thanks in Advance

I'm seeing this as well (rails 4.2.11), and agree: no docs indicate access of flash should be necessary.
But, if I have a page that sets flash[:blah] = 'applesauce' and consumes the flash (e.g., puts flash[:blah]) on the next request, that key is not present in the following request. If I don't, it will linger through request after request until I hit a one where I check the flash.
My workaround is this:
In application_controller.rb
class ApplicationController < ActionController::Base
before_action :touch_flash
#...
def touch_flash
flash
end
end
This act of referencing flash appears to be enough to trigger a discard at end of the request (but doesn't interfere with any actual access later in the request). Next request, it's gone as expected.

Related

Creating a custom view

I am trying to create a landing page for an event for people to visit to see the events details. I have created the view, added a route to the event resources and made changes to the controller but something has been done incorrectly.
Here is my code:
routes.rb:
resources :events do
resources :guests
match '/landing_page', to:'events#landing_page', as: :landing_page, :via =>[:get, :post]
# resources :guestlists
end
event_controller:
def landing_page
#event = Event.find(params[:id])
end
When I open the landing page i get the following error:
"ActiveRecord::RecordNotFound (Couldn't find Event without an ID):"
In case anyone else runs into this, I wanted to document Sergio's last comment here which I believe leads to the outcome I think most people will be looking for. Nesting this inside of a member block should get you an ideal outcome:
resources :events do
member do
get :landing_page
end
end
Running rake routes should now show /events/:id/landing_page(.:format) so you can use the same method you use in your show method that just asks for params[:id].
I was wracking my brain for a while on this as rails resources seem to be dwindling on the interwebs.

Validation & External APIs - Rescue in Controller or Fatten Model validations?

I am using Restforce to query records from a remote salesforce instance. The user simply has to put in a valid UID for the record they want to query.
Restforce uses Faraday middleware to deal with http requests - and raises a Faraday::ResourceNotFound error if I request something that cannot be located in the remote salesforce database.
Question
Where should I validate user input?
I have two ideas but i'm not sure of the consequences to each... and I'm trying to work out how to stick best to the fat model - skinny controller best practice.
Check for successful query at the application controller level
Requests save the UID to a simple ActiveRecord model #record_request. My create method can fire a query, check for an error and flash/redirect the user if needed.
# app/controllers/record_requests_controller
def create
#record_request = current_user.record_requests.new(record_request_params)
# Check to see if CHAIN number exists
if #record_request.restforce.find("Contact", #record_request.chain_number, 'ClientID__c')
# If it gets past that do standard validation checks
if #record_request.save
flash[:success] = 'Record request was successfully created.'
redirect_to record_requests_path
else
render :new
end
end
end
Then over in the ApplicationController I've got a rescue method setup
# app/controllers/application_controller
rescue_from Faraday::ResourceNotFound, with: :resource_not_found
private
def resource_not_found
flash[:alert] = 'Cannot find resource on Salesforce'
redirect_to(:back)
end
This works! And seems fine... but...
Model level validation?
My gut tells me this is a validation and should be validated on the model level, what if there's a bug and something sneaks into my database? Should this all just be checked at the if #record_request.save moment?
If so... how would i get model level code to handle validation AND be able to fire off an external (OAuth authenticated) API request without breaking the MVC.
What are the implications to either, and how might I do better?
I think the best way to use model level validation something like this:
validate :something
def something
errors.add(:field, 'error message') unless RestClient.check_something
end
Where RestClient is singleton object in /lib folder. This will allow to keep controller clean.

Devise: Is it possible to NOT send a confirmation email in specific cases ? (even when confirmable is active)

Here is my situation, I use devise to allow users to create account on
my site and manage their authentication.
During the registration process I allow customers to change some
options, leading to an actually different account being created but
still based on the same core user resource.
I would like to choose not to send a confirmation email for some of
those account types. I don't care if the account do not get confirmed
and user cannot log in, that's ok, no pb with that.
How would I go about doing that ?
Thanks,
Alex
Actually it's quite easy once I dig a little deeper.
Just override one method in your User model (or whatever you are using):
# Callback to overwrite if confirmation is required or not.
def confirmation_required?
!confirmed?
end
Put your conditions and job's done !
Alex
If you just want to skip sending the email but not doing confirmation, use:
# Skips sending the confirmation/reconfirmation notification email after_create/after_update. Unlike
# #skip_confirmation!, record still requires confirmation.
#user.skip_confirmation_notification!
If you don't want to call this in your model with a callback overwrite this method:
def send_confirmation_notification?
false
end
You can also simply add the following line of code in your controller before creating the new user:
#user.skip_confirmation!
I don't know if Devise added this after the other answers were submitted, but the code for this is right there in confirmable.rb:
# If you don't want confirmation to be sent on create, neither a code
# to be generated, call skip_confirmation!
def skip_confirmation!
self.confirmed_at = Time.now
end
I was able to do something similar with the functions:
registrations_controller.rb
def build_resource(*args)
super
if session[:omniauth] # TODO -- what about the case where they have a session, but are not logged in?
#user.apply_omniauth(session[:omniauth])
#user.mark_as_confirmed # we don't need to confirm the account if they are using external authentication
# #user.valid?
end
end
And then in my user model:
user.rb
def mark_as_confirmed
self.confirmation_token = nil
self.confirmed_at = Time.now
end

Get absolute (base) url in sinatra

Right now, I do a
get '/' do
set :base_url, "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}"
# ...
haml :index
end
to be able to use options.base_url in the HAML index.haml.
But I am sure there is a far better, DRY, way of doing this. Yet I cannot see, nor find it. (I am new to Sinatra :))
Somehow, outside of get, I don't have request.env available, or so it seems. So putting it in an include did not work.
How do you get your base url?
You can get it using request.base_url too =D (take a look at rack/request.rb)
A couple things.
set is a class level method, which means you are modifying the whole app's state with each request
The above is a problem because potentially, the base url could be different on different requests eg http://foo.com and https://foo.com or if you have multiple domains pointed at the same app server using DNS
A better tactic might be to define a helper
helpers do
def base_url
#base_url ||= "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}"
end
end
If you need the base url outside of responding to queries(not in a get/post/put/delete block or a view), it would be better to set it manually somewhere.

Adding a flash after authentication with merb-auth

What's the best way to add a flash message, for successful or unsuccessful login when using the merb-auth slice (Other than overriding sessions create)?
Hey deimos. If you want to add an message without overwriting the create action you can always use an after filter. Something like
...........
after :set_login_flash, :only => [:create]
private
def set_login_flash
flash[:error] = "You're not logged in" unless logged_in?
end
..........
You'll need to tune it to use the appropriate flash system that you're using in your application but something like that should work for you.

Resources