According to the official flash section on Rails Guide:
The Flash
The flash is a special part of the session which is cleared with each request. This means that values stored there will only be available in the next request, which is useful for passing error messages etc.
...
flash.now
By default, adding values to the flash will make them available to the next request, but sometimes you may want to access those values in the same request.
However, after doing some test, I found that flash is available in the current & next request. And flash.now is only available in the current request.
Is the Rails Guide incorrect? Or maybe I miss something?
# Controller action
def test_flash
flash[:notice] = "This is a flash msg."
end
# test_flash.html.erb
<% flash.each do |name, msg| -%>
<%= content_tag :div, msg, class: name %>
<% end -%>
I won't say the document is incorrect, but I agree it could be more clear.
It should be phrased something like:
Flash is clear after next request, therefore it's available in the current
request and next request. If you only want it be available in the current
request, not along with the next request, use flash.now.
On the other hand, don't you think something is not available in the current
request, given current flash API, as a hash like object, it would be quite
weird? For example:
flash[:notice] = 'nnf'
puts flash[:notice] # => nil
It would make more sense with write and read if that's the case.
You have read it incorrectly. flash.now is only available to the current request. flash (without now) is the only one that will be available to the next request.
The sentence you read above - is actually talking about plain flash (to begin with), and only then introduces flash.now as a contrast at the end of the paragraph.
Related
I have a form in RoR with a controller action that looks up a record via the get parameter.
def respond
if request.post?
# Submit logic here...
# cannot lookup this way to fill the form out again
# #current_message = Saved_message.find_by_id(params[:msg_id])
elsif request.get?
#current_message = Saved_message.find_by_id(params[:msg_id])
end
end
I can't use the params[:msg_id] to lookup the message again because it's a post request and I don't resend the get parameters. However, the get parameters remain in the url such as .../messages/respond?msg_id=2. I can get around this by passing in a hidden field with a different parameter name like <%= form.hidden_field :msg_id_2, value: params[:msg_id] %>. Then I can lookup the #current_message via the params[:msg_id_2]. However, I don't like this solution. Any advice to access the now inaccessible get parameter?
you should use RESTful routes so that you do not have to care about such issues.
since you are not posting much about the actual code or problem you are trying to solve, i can just assume what might be the issue here and how to solve it.
I am trying to send an sms to a number entered in an input field using Nexmo gem
This is what I have so far and it doesn't seem to work
pages/test.html.erb
<%= form_tag "/pages/send_sms" do -%>
<%= text_field_tag "number" %>
<%= submit_tag "Send" %>
<% end -%>
routes.rb
Rails.application.routes.draw do
get 'pages/home'
post '/pages/send_sms', as: 'send_sms'
get 'test', to: 'pages#test'
root 'pages#home'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
pages_controller.rb
def send_sms
#number = params[:number]
nexmo = Nexmo::Client.new(
key: ENV['NEXMO_API_KEY'],
secret: ENV['NEXMO_API_SECRET']
)
notification = "Download the app through this link"
response = nexmo.send_message(
from: "GLAM360",
to: params['number'],
text: notification
)
if response['messages'].first['status'] == '0'
redirect_to root_path
end
end
This is what I see in the terminal
Started POST "/pages/send_sms" for 127.0.0.1 at 2017-10-08 00:35:45 +0400
Processing by PagesController#send_sms as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"zPj5PcZrD+uNYxvvfDio8B5uNWitg0vMw+3Vm8KbvQumbNWzsgN4sBJDKsi2srx0rSatiOISegWHQFE860
JxcA==", "number"=>"+971585959698", "commit"=>"Send"}
No template found for PagesController#send_sms, rendering head :no_content
Completed 204 No Content in 803ms
Any help will be highly appreciated here
The error itself tells you what to do. You have few options.
First for your case, just add another redirect if the last check
condition fails. In your case, its failing and so asking for default template. If you specify an else clause, in which you
describe where should it go to (say to the form again with an alert message), rails will itself take care of that.
if response['messages'].first['status'] == '0'
redirect_to root_path
else
redirect_to test_path
end
I used your script and added a send_sms.html.erb with a status
variable being passed from the controller according to the response
of the nexmo.send_message function. Like "Success" or failure and
everything works fine, on the webpage it informs me about the status and I received a text message as well. This is what I will prefer for a better UX.
.
If I have to do it, there would be a lot of changes I would do to the script. A suggestion would be to never rely on an external API, always wrap the interactions you do to an external API in an interface. I will wrap the Nextio scripts, take it out of the controller and place them in an interface (Have a class in either lib or a wrapper function in helper and use interface to interact with it) and will interact with it through my controller. Try not to put logic in your controller. I would also use begin rescue block for interactions with external API and will read about all the errors and think about how to handle them. Lastly for the flow, I would give users more information and not keep them hanging. I would redirect them to another page like send_sms and give them status or use alert messages to tell them whats the status.
Lastly, I would use background tasks for these jobs (which can take sometime depending upon external servers). Use something like sidekiq.
I have a controller like this in my project:
class BriefcasesController < ApplicationController
...
def update
#super_power = SuperPower.find(params[:super_power_id])
#briefcase.contents.delete(params[:super_power_id].to_s)
flash[:notice] = "Successfully removed #{view_context.link_to(#super_power.title, super_power_path(#super_power)} from your briefcase."
redirect_back(fallback_location: '/briefcase'
end
end
The link_to helper is not rendering a link to the browser, rather it's printing the html: Successfully removed <a href=\"/powers/1\>flying</a> from your briefcase. I've also tried using the method #html_safe on the flash message to no avail. I'm wondering if there's a way to fix this using view_context or if there's a better way to include a link inside a Flash message.
You need to use html_safe when outputting the flash messages - not when storing them.
<% flash.each do |key, msg| -%>
<%= content_tag :div, msg.html_safe, class: name %>
<% end -%>
.html_safe just sets a flag on the string object that its trusted and should not be escaped.
The flash works by storing flash messages in the session storage - by default this means a cookie in the browser.
So when you do:
flash[:notice] = "foo"
You're storing the raw string "foo" in a cookie* and its unpacked back into the session on the next request. But the string is not the same Ruby object - so the html_safe flag on the string object is not persistent.
Note: the following only works with relatively old versions of Rails (confirmed in 4.0 and before, possibly in 4.1). Rails used to allow custom objects to be passed in flash messages, but later changed it to only allow primitive objects (documented at https://github.com/rails/rails/issues/15522).
You need to call html_safe on the entire string. Using string interpolation ("#{some_ruby_code}") changes the "safe" link_to string back into a regular string that gets escaped.
In my controller I have an if condition and I want an alert/confirmation box to pop up if it is satisfied, then when the user clicks "ok" to redirect to another page.
I've tried
flash[:alert] = 'Successfully checked in'
redirect_to check_in_path
However it just skips the alert part and goes straight to the redirect without an alert message.
My Ruby version is ruby 2.2.6p396 and rails is 5.0.1
Any help would be appreciated
You need to create a js.erb file. You can then use your existing rails code along with a js alert box. Js.erb files let you combine rails and JavaScript code in the same file. As mentioned flash[:alert] is not an alert box, alert is a css class.
Rails is limited to the respond to HTTP request with HTML. And what you describe sounds more like a JavaScript alert. What you tried, if configured properly*, will simply show the flash alert when the check_in_path page is rendered.
* Get familiar with how the flash works, Rails Guides
You have your controller set up correctly. The only other part I meant by configured correctly is that in your views you should display said flash message:
<% flash.each do |name, msg| -%>
<%= content_tag :div, msg, class: name %>
<% end -%>
It's common to use the name of the flash to style it to make to make it's intent clear; commonly red for failure, green for success.
you can do it as follows
render :update do |page|
page << "alert('Successfully checked in')"
page.redirect_to check_in_path
end
but partial rendering in controller is most commonly used together with Ajax calls. so you may have to make an ajax call to your action from your view page. Hope this will help you
I think this is a pretty simple question but nothing I've read has answered my question directly:
I have a new products page with a standard form. After successfully submitting the form, I redirect to a custom controller action and view called "thanks".
On the "thanks" page, I want to be able to print the name of the product just created and possibly some other attributes.
How do I pass the object just created into my new action? Right now the controller looks like this:
def create
#product = Product.new(params[:product])
if #product.save
flash[:notice] = "Successfully created Product."
redirect_to thanks_path
else
render :action => 'new'
end
end
def thanks
end
You can't send object through redirect.
There are three ways to solve your problem:
Render the 'thanks' template directly(not action #thanks)
render 'thanks' # thanks template
You can send whatever instance variable to this template directly. #thanks is no longer needed in this case.
Drawback: The url won't be changed.
Convey messages through session
If you want to show certain messages, you can prepare it in #create and send it through session or flash(part of session actually). flash is better as you don't need to clear it manually.
Note: You may want to use ActiveRecord as session storage if the message size is big, otherwise you'll meet CookiesOverflow by default setting.
Send very simple message through session say obj_id
Similar to #2 but I thinks this is better than #2. In #thanks, you can construct complex message according to if obj_id is present, what is the id and then find related data through db.
You have two fairly decent options.
First, you could adjust the thanks_path route to take an id parameter, and call it like redirect_to thanks_path(#product). Then you can call it up in your thank you method like any standard show method. It might be worth mentioning that if you are going to be displaying sensitive information on the thank you screen, you may want to use a random uuid, instead of an id, to look up the product.
A better way might be to not redirect at all, but rather adjust your view from simply drawing the form to something like this:
<% if #product && !#product.new_record %>
THANK YOU MESSAGE GOES HERE
<% else %>
EXISTING FORM GOES HERE
<% end %>