I'm developing a facebook app so I can't rely on cookies due to P3P (Privacy Preferences Project) and yep, it's a damn pain (see slides 18 and 19 on this slideshare about Rails and Facebook apps for a picture of it)...
In a facebook app every cookie, from browsers perspective, is a third-party cookie. And many browsers block them by default.
So my question is: How can I implement flash messages without rely on cookies?
UPDATE:
I modified session_store.rb and the DB accordingly. Now the sessions are stored on DB but the flash messages are still relying on cookies... Any idea please?
UPDATE#2:
I finally found a workaround, see my answer below. Best thing to do would be to ajax everything (according to the above-linked slideshare) but as a quick fix my solution should work.
I finally found a workaround implementing my own (simple) flash messages and passing them through the params from one request to another.
First of all, I overwritten default_url_options in application_controller.rb to append to every request a :my_flash param:
def default_url_options
{ :my_flash => #my_flash }
end
Then, always in application_controller.rb, I wrote a my_flash_from_params before_filter to set the #my_flash variable:
def my_flash_from_params
#my_flash = params[:fb_flash]
end
Finally I rendered the following _my_flash.html.erb partial in application.html.erb
<div class="my_flash">
<%= my_flash %>
</div>
Calling:
<%= render :partial => "layouts/my_flash", :locals => {:my_flash => #my_flash} if #my_flash %>
If you want to try this solution see also this answer about default_url_options rewriting.
Flash messages are built on top of the session. So you could still rely on the flash if you change the session store to use the database. This can be easily done by editing config/initializers/session_store.rb and following the instructions on that file.
Here's more information on the topic: Action Controller Overview -> Session
Related
I am trying to build a website in Rails 4 to track users redirects and site element views.
I decided to use session ids which I believe are quite unique in the short term but I'm having a strange issue.
Example procedure:
user follows a redirect, the system stores this action with a Session ID, let's say xxx
user reaches destination page, which contains a tracker, the system stores this action with ANOTHER Session ID, yyy
user reaches another page which also contains a tracker, the system stores this action with Session ID yyy
After the second action is stored, the session ID stays the same yyy for every request after that, but I need to have the same session ID every time.
In session I also store a SecureRandom.hex generated code, which also changes from the first to the second request (which is not a surprise, since the session ID changes).
I also tried using a cookie, same result.
Please notice that these redirects are external, but all the requests are then made to the same domain (exactly the same, without www and in https).
Any idea?
Thanks in advance.
Update
this is the source code responsible for managing redirects:
before_action :load_redirect, :only => [:http_redirect]
def http_redirect
raise ActionController::RoutingError.new('Redirect has been disabled') unless #redir.enabled
ua = UserAction.create(
:session_id => session.id,
:user_agent => request.user_agent,
:trackable => #redir,
:ip_address => request.remote_ip,
:referer => request.referer
)
redirect_to #redir.destination_url
end
private
def load_redirect
#redir = Redirect.find(params[:id])
end
UPDATE:
Since you are using an iframe (per comment discussion below) for tracking code, the issue is likely that on the external site cookies are not being passed from parent page to the iframe because the iframes origin (domain) is different from the parent page.
OLD ANSWER:
(Still could be helpful for others debugging similar issues)
Source code would help. Without that, here are a few things to try:
Try disabling CSRF protection for the external tracking link action (I'm assuming it POSTs or PUTs data from an external source). CSRF protection could be creating a new or null session for those requests. Put this in the controller that contains the action accepting data from the external source:
protect_from_forgery :except => [:your_action]
The redirect (especially if it's a 301) could be cached in the browser you are using, hence having a different cookie and session than the request your tracking code makes. The stale cookie would be part of the cached redirect.
Try putting cache control headers on your controller action that does the redirect.
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
response.headers['Pragma'] = 'no-cache'
response.headers['Expires'] = '0'
Your browser may not support setting cookies on a redirect, or possibly third-party cookies. Try in a different modern browser?
There could be a bug in your code. If these solutions don't work, maybe post it?
I am an experienced PHP developer but new to RoR and trying to understand how every thing works. I know how to use flash hash i.e in my action method, I'll set
flash[:notice] = 'some message'
and in my view, i'll display that.
This mechanism is also implemented in Yii framework. I understand how it works there. The thing that I don't understand is how it actually works here in RoR. flash is just a local variable then how can I access it in my views?
flash is actually a method. It's not in your controller, but the Rails controller delegates it to the request object. So the flash method is defined in the request object, but you can access it from your controllers, and from the view.
Check the link to the ActionDispatch::Request code. The flash is actually stored inside the session when set. The next time the user requests a page, the flash is accessible for use in the views.
In your view you can just access it like this:
<%= flash[:notice] %>
Or in a aesthetically more pleasant way (this can only be done with notice and alert since they're so frequently used):
<%= flash.notice %>
See the documentation for more information.
'flash' is not a local variable. It is part of session like 'session' hash. What this implies is that session hashes (flash, session, cookies) are shared values between ActionController::Base and ActionView::Base. Therefore session hashes are accessible from controllers and from views.In order to access flash in views, just use it as you would use it in controller. Referring to your earlier code , you would print notice like this:
<% if flash[:notice] %>
<p><%= flash[:notice] %></p>
<% end %>
For further reference on this topic please checkout: guides
The flash hash is basically a variable which is populated with each controller/action request, and then is reset after the request has been performed. As Adilbiy Kanzitdinov has mentioned - it's set in the session hash :
The flash provides a way to pass temporary objects between actions.
Anything you place in the flash will be exposed to the very next
action and then cleared out. This is a great way of doing notices and
alerts, such as a create action that sets flash[:notice] = "Post
successfully created" before redirecting to a display action that can
then expose the flash to its template. Actually, that exposure is
automatically done.
You need to remember that ROR is full-stack, meaning it has a bunch of middleware it uses to create the most efficient responses for your users. This allows you to set local variables (session, params, flash are 3 I can think of)
To call from a view, you just need to reference this local variable, as below:
<%= flash[:key] %>
I am relatively new to rails and right now I am developing a simple log in log out system.
In my app when I log in the URL generated is:
localhost:3000/user/index/7
When I log out I get back to the root. But if copy this URL and paste it in another browser window i get instantly logged in without being directed to the log in form. How to correct this issue.
I tried to store user id in session hash and then upon logout i have set user id in session to be nil. But that does not work. Help needed.
Edited:
In my Home controller
class HomeController < ApplicationController
def signin
user=User.find(:all,:conditions=>["user_login=? AND user_password=?",params[:user] [:username],params[:user][:password]);
if user!=nil
session[:user_id]=user.user_id;
redirect_to({:controller=>'user'})
end
end
end
In User controller i have a logout method:
def logout
session[:user_id]=nil;
redirect_to({:controller=>'home'});
end
My routes.rb file looks like this:
ActionController::Routing::Routes.draw do |map|
map.root :controller => "home",:action => "index"
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
Edited:
I have solved this issue I was not checking id value in session hash in User controller index method. But I have another question If i have an app in rails 2.3.17 and I want to shift it to latest version how much changes will I have to make
You can set before_filter for those actions in the controller. using that before_filter you can check session is nil or value is present.
Otherwise you can follow this railscasts video
http://railscasts.com/episodes/250-authentication-from-scratch
This is the default behavior of the basic authentication. Once you get logged in, all your credentials are stored in the session headers which is maintained by the browser. If your clear your cache, then it should prompt for the password again....
I really recommend to use an existing authentication systems, like https://github.com/plataformatec/devise
On this site you can easily get an overview about other existing systems, and of there popularity and development activity.
https://www.ruby-toolbox.com/categories/rails_authentication
You really don´t have to program such stuff by yourself, but if you really like to do it, maybe this could also helps you: http://railscasts.com/episodes/250-authentication-from-scratch-revised. But I recommend devise absolutely.
I think you are trying to reinvent the wheel here. You can use has_secure_password inside your User model and generate a sessions_controller to handle the create and destroy. the methods are basically the same, but with the has_secure_password flag. You should then take care of destroying the session properly.
I am relatively new to rails and right now I am developing a simple log in log out system.
In my app when I log in the URL generated is:
localhost:3000/user/index/7
When I log out I get back to the root. But if copy this URL and paste it in another browser window i get instantly logged in without being directed to the log in form. How to correct this issue.
I tried to store user id in session hash and then upon logout i have set user id in session to be nil. But that does not work. Help needed.
Edited:
In my Home controller
class HomeController < ApplicationController
def signin
user=User.find(:all,:conditions=>["user_login=? AND user_password=?",params[:user] [:username],params[:user][:password]);
if user!=nil
session[:user_id]=user.user_id;
redirect_to({:controller=>'user'})
end
end
end
In User controller i have a logout method:
def logout
session[:user_id]=nil;
redirect_to({:controller=>'home'});
end
My routes.rb file looks like this:
ActionController::Routing::Routes.draw do |map|
map.root :controller => "home",:action => "index"
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
Edited:
I have solved this issue I was not checking id value in session hash in User controller index method. But I have another question If i have an app in rails 2.3.17 and I want to shift it to latest version how much changes will I have to make
You can set before_filter for those actions in the controller. using that before_filter you can check session is nil or value is present.
Otherwise you can follow this railscasts video
http://railscasts.com/episodes/250-authentication-from-scratch
This is the default behavior of the basic authentication. Once you get logged in, all your credentials are stored in the session headers which is maintained by the browser. If your clear your cache, then it should prompt for the password again....
I really recommend to use an existing authentication systems, like https://github.com/plataformatec/devise
On this site you can easily get an overview about other existing systems, and of there popularity and development activity.
https://www.ruby-toolbox.com/categories/rails_authentication
You really don´t have to program such stuff by yourself, but if you really like to do it, maybe this could also helps you: http://railscasts.com/episodes/250-authentication-from-scratch-revised. But I recommend devise absolutely.
I think you are trying to reinvent the wheel here. You can use has_secure_password inside your User model and generate a sessions_controller to handle the create and destroy. the methods are basically the same, but with the has_secure_password flag. You should then take care of destroying the session properly.
Introduction:
I am building a facebook app which auto wishes happy birthday. I am building it in Rails and using a ruby API wrapper called fb_graph. The creator of fb_graph has graciously provided a working sample application fb_graph_sample
After playing around with it, I do not understand how the sessions/cookies work. For example, check out this code:
def require_authentication
authenticate Facebook.find_by_id(session[:current_user])
rescue Unauthorized => e
redirect_to root_url and return false
end
def authenticate(user)
raise Unauthorized unless user
session[:current_user] = user.id
end
Where does session[:current_user] comes from?
Under config/initializers/session_store.rb,
FbGraphSample::Application.config.session_store :cookie_store, :key => '_fb_graph_sample_session'
So, I look at the cookies for localhost which is where I am deploying it as using Chrome inspector tools, I see _fb_graph_sample_session with value, domain, path, expires, size, http, etc...
I still don't see how session[:current_user] comes about? Looking at the development.sqlite3 file, there is only 1 data for the facebook model. The id is 1 so, that leads me to believe that [:current_user] is 1 and the code is calling 'authenticate Facebook.find_by_id(1)'
Can someone please explain how session[:current_user] translate to 1? I read railstutorial.org chapter on signing-in-out and it creates a sessions controller but there is no sessions controller in the fb_graph_sample app.
Thanks,
I get's set in the authenticate method:
session[:current_user] = user.id
The app is using cookie based session store, when a user logs in a cookie (think of it as a special hash) is written to his browser. You use session pretty much as a hash, you can set as shown above, or get, i.e.
<%= "logged in as #{User.find(session[:current_user]).name}" %>