Defining time parameters in rails environment files - ruby-on-rails

I have lots of different timeouts for various cookies through out my app.
If I move these settings to be centralized in the Rails configuration files will they work properly since the environment variables is initialised only once when the application loads or am I mistaken?
In other words: will the timeout be set to when the cookie was created or will the timeout be set according to when the app loaded?
TODAY
cookies['locale'] = {
:value => current_user && current_user.locale || 'en',
:expires => 1.week.from_now
}
TOMORROW
cookies['locale'] = {
:value => current_user && current_user.locale || 'en',
:expires => Application.config.locale_timeout
}
config/environments/qa.rb
config.locale_timeout = 1.week.from_now

In other words: will the timeout be set to when the cookie was created
or will the timeout be set according to when the app loaded
the timeout be set according to when the app loaded
So,
In my opinion, The correct way is to define Time offset in config:
Application.config.locale_timeout = 1.week
Then you will use it like this
:expires => Time.current + Application.config.locale_timeout
OR
:expires => Application.config.locale_timeout.from_now

Related

Rails cached value lost/nil despite expires_in 24.hours

I am using ruby 2.3.3 and Rails 4.2.8 with Puma (1 worker, 5 threads) and on my admin (i.e. not critical) page I want to show some stats (integer values) from my database. Some requests take quite a long time to perform so I decided to cache these values and use a rake task to re-write them every day.
Admin#index controller
require 'timeout'
begin
timeout(8) do
#products_a = Rails.cache.fetch('products_a', :expires_in => 24.hours) { Product.where(heavy_condition_a).size }
#products_b = Rails.cache.fetch('products_b', :expires_in => 24.hours) { Product.where(heavy_condition_b).size }
#products_c = Rails.cache.fetch('products_c', :expires_in => 24.hours) { Product.where(heavy_condition_c).size }
#products_d = Rails.cache.fetch('products_d', :expires_in => 24.hours) { Product.where(heavy_condition_d).size }
end
rescue Timeout::Error
#products_a = 999
#products_b = 999
#products_c = 999
#products_d = 999
end
Admin#index view
<li>Products A: <%= #products_a %></li>
<li>Products B: <%= #products_b %></li>
<li>Products C: <%= #products_c %></li>
<li>Products D: <%= #products_d %></li>
Rake task
task :set_admin_index_stats => :environment do
Rails.cache.write('products_a', Product.where(heavy_condition_a).size, :expires_in => 24.hours)
Rails.cache.write('products_b', Product.where(heavy_condition_b).size, :expires_in => 24.hours)
Rails.cache.write('products_c', Product.where(heavy_condition_c).size, :expires_in => 24.hours)
Rails.cache.write('products_d', Product.where(heavy_condition_d).size, :expires_in => 24.hours)
end
I am using this in production and use Memcachier (on Heroku) as a cache store. I also use it for page caching on the website and it works fine there. I have:
production.rb
config.cache_store = :dalli_store
The problem I am experiencing is that the cached values disappear almost instantly, and quite intermittently, from the cache. In the console I have tried:
I Rails.cache.write one value (e.g. product_a) and check it a minute later, it is still there. Although crude, I can see the "Set cmds" increments by one in Memcachier admin tool.
However, when I add the next value (e.g. product_b) the first one disappears (becomes nil)! Sometimes if I add all 4 values, 2 seems to stick. These are not always the same values. It is like whack-a-mole!
If I run the rake to write the values and then try to read the values typically only two values are left, whereas the others are lost.
I have seen a similar question related to this where the reason explained was the use of a multithread server. The cached value was saved in one thread and could not be reached in another, the solution was to use a memcache, which I do.
It is not only the console. If I just reload admin#index view to store the values or run the rake task, I experience the same problem. The values do not stick.
My suspicion is that I am either not using the Rails.cache-commands properly or that these commands do not in fact use Memcachier. I have not been able to determine whether my values are in fact stored in Memcachier but when I use my first command in the console I do get the following:
Rails.cache.read('products_a')
Dalli::Server#connect mc1.dev.eu.ec2.memcachier.com:11211
Dalli/SASL authenticating as abc123
Dalli/SASL authenticating as abc123
Dalli/SASL: abc123
Dalli/SASL: abc123
=> 0
but I do not get that for subsequent writes (which I assume is a matter of readability in the console and not a proof of Memcachier not being used.
What am I missing here? Why won't the values stick in my cache?
Heroku DevCenter states a little different cache config and gives some advice about threaded Rails app servers like Puma using connection_pool gem:
config.cache_store = :mem_cache_store,
(ENV["MEMCACHIER_SERVERS"] || "").split(","),
{ :username => ENV["MEMCACHIER_USERNAME"],
:password => ENV["MEMCACHIER_PASSWORD"],
:failover => true,
:socket_timeout => 1.5,
:socket_failure_delay => 0.2,
:down_retry_delay => 60,
:pool_size => 5
}

Unable to set/use session variables in ruby on rails controller

Can somebody tell me the right way to set/use session variables in a ruby on rails application from scratch. I am not able to set/use a session variable in my controller between two pages. I am using CookieStore session type. This is the syntax being used to set and get session variables:
session[:test] = "testing"
#test_str = session[:test]
Let me know in case I am missing on something.
This is how my controller looks like:
class PaymentsController < ApplicationController
# GET /merchant_test
def merchant_test
session[:test] = "testing"
render :layout => false
end
# POST /post_to_mobikwik
def post_to_mobikwik
zr = Mobikwik::Request.new(params)
#mobikwik_data = zr.all_params
#test_str = session[:test]
render :layout => false
end
# POST /z_response
def z_response
zr = Mobikwik::Response.new(request.raw_post)
#checksum_check = zr.valid?
#mobikwik_post = zr.all_params
#statuscode = #mobikwik_post['statuscode']
#statusmessage = #mobikwik_post['statusmessage']
if #statuscode == "0"
#verified = zr.verified?
else
#verified = false
end
render :layout => false
end
Your session cookie settings might be wrong. You should inspect the headers of the response and see what the Set-Cookie header looks like.
It might have a wrong domain or perhaps your cookie is https only and you're on http.
The configuration is usually done in some place like config/initializers/session_store.rb
Myapp::Application.config.session_store :cookie_store, {
:key => '_appname_session_id',
:path => '/',
:domain => nil, # accepted domain, for example '.example.com'
:expire_after => nil, # the session will be expired in X seconds unless active
:secure => false, # if true, cookie is valid only on https
:httponly => true # if true, javascript can't access the cookie
}
Try this in config/initializers/session_store.rb
AppName::Application.config.session_store :cookie_store, key: '_app-name_session'
As a rule of thumb, in rails we create a method
in ApplicationController, called current_user
In this free RailsCast, you see exactly are you need:

Rails 3 additional session configuration options (key, expires_after, secure)

Can someone point out what the new Rails 3.x session configuration options are?
I'm trying to duplicate the same configuration that I have in my Rails 2.3.x application.
This is the configuration that I used in the application:
#environment.rb
config.action_controller.session_store = :active_record_store
config.action_controller.session = {
:key => '_something', #non-secure for development
:secret => 'really long random string'
}
# production.rb - override environment.rb for production
config.action_controller.session = {
:key => '_something_secure',
:secret => 'really long random string',
:expire_after => 60*60,#time in seconds
:secure => true #The session will now not be sent or received on HTTP requests.
}
However, in Rails 3.x, I can only find mention of the following:
AppName::Application.config.session_store :active_record_store
AppName::Application.config.secret_token = 'really long random string'
AppName::Application.config.cookie_secret = 'another really long random string'
Are there other config settings to control the key, expire_after time, and secure option?
Regarding the latter, if "config.force_ssl = true" is set in production.rb, I assume the secure option is no longer required?
Thanks very much!
You now configure the Cookie-based session store through an initializer, probably in config/initializers/session_store.rb. In Rails 3 the session store is a piece of middleware, and the configuration options are passed in with a single call to config.session_store:
Your::Application.config.session_store :cookie_store, :key => '_session'
You can put any extra options you want in the hash with :key, e.g.
Your::Application.config.session_store :cookie_store, {
:key => '_session_id',
:path => '/',
:domain => nil,
:expire_after => nil,
:secure => false,
:httponly => true,
:cookie_only => true
}
(Those are just the standard defaults)
If you force SSL in production then setting secure on the cookie shouldn't really make a difference in practice, but you might want to set it just to be on the safe side...
Your::Application.config.session_store :cookie_store, {
:key => '_session_id',
:secure => Rails.env.production?
}

Rails 3: Can't seem to write cookies for top level domain :(

I setup the cookie store to domain => :all, like I could find in documentation and it seems to work, because devise's authentication works across the multiple domain.
MyApp::Application.config.session_store :cookie_store, :key => '_MyApp.com_session', :domain => :all
However when I am trying myself to write to a cookie, it always write down the sub domain... I don't get it:
I write the cookie in the simplest manner possible:
cookies.permanent[:remember_locale] = locale
But no matter what it won't set it for the top level domain whereas the one dropped by devise seems to manage it without a problem :(
Alex
ps: I am using rails 3.0.3
The configuration for the session_store only applies to the session cookie. When setting a separate cookie you have to specify the domain for that cookie as well.
cookies.permanent[:remember_locale] = { :value => locale, :domain => :all }
Note (pulled from rails source):
# Please note that if you specify a :domain when setting a cookie, you must also specify the domain when deleting the cookie:
#
# cookies[:key] = {
# :value => 'a yummy cookie',
# :expires => 1.year.from_now,
# :domain => 'domain.com'
# }
#
# cookies.delete(:key, :domain => 'domain.com')

How do I manipulate my session's expiry time after Rails app initialization?

I'm using the dalli memcached client for session storage in my Rails app. I'd like to allow users to check a 'Keep me signed in' box when they login to the app, which will cause the session to expire after a month or something. It's pretty straightforward to set the expiration time in the app initialization:
config/initializers/session_store.rb
require 'action_dispatch/middleware/session/dalli_store'
Rails.application.config.session_store :dalli_store, :memcache_server => ['host1', 'host2'], :namespace => 'sessions', :key => '_foundation_session', :expire_after => 30.minutes
But how would I go about manipulating :expire_after after the app has been initialized?
Im not sure this work for you , but
in Rails 2.3 with db session store you could use somthing similar in your action .
request.session_options = request.session_options.dup
request.session_options[:expire_after] = 5.minutes
request.session_options.freeze
I hope it is useful
edit:
I found this new article for rails3
http://augustl.com/blog/2010/dynamic_session_expiration_time_in_rails_3
I hope it is useful

Resources