Make action cache from script in Rails - ruby-on-rails

I want to make action cache from my script without reference to domain name, because we don't know unicorn's address. So, I must call controller's action in some 'internal' way.
I tried
app = ActionDispatch::Integration::Session.new(Rails.application)
app.get(app.api_v1_items_url)
But, this seems to produce cache in different location (I don't know where) than a location in which Rails.cache.clear clears cache. Any idea?
EDIT
Our controller implementation is
class Api::V1::ItemsController < Api::V1::ApplicationController
caches_action :index, cache_path: Proc.new { api_v1_items_path }
def index
...
So, domain name is not included in cache path.

Sorry, my solution is not wrong. I make some rails s restarting mistake.

Related

Rails 6: How to load global variables only once?

My app uses global variables like logos, app name, etc retrieved from the database and shown on different controllers and views. I put it in ApplicationController to be available to all, but I find that the individual controllers repeat the same query sometimes.
class ApplicationController < ActionController::Base
$image = Setting.find_by_name('image').value
$city = Setting.find_by_name('city').value
$currency = Setting.find_by_name('currency').value
end
Is there a way to make the same variables available to all controllers (and users) with just a one-time query with the variables saved on memory, such as when the app starts up?
You could attempt to use initializers.
Rail will load all files in config/initializers/ folder when the server starts up. This can work as a place to initialize application-wide variables. We could create a file inventory.rb file in the initializers directory:
at config/initializers/inventory.rb
module Inventory
class Count
Orders = Order.all
end
end
Inventory::Count::Orders
# => "[your orders will show here]"
These will only be loaded once when the server is started or restarted. As such this works well if the values you need won't change. If they will change I don't think there is a good way to avoid running multiple queries.
Whats about caching? Rails is using SQL Caching and you can use Low Level Caching. See the guides (1.7 and 1.8): https://guides.rubyonrails.org/caching_with_rails.html#low-level-caching

Rails 3 file_store caching, delete expired fragments

I have a Rails 3.2.11 application running on Unicorn and is set up for file_store caching to a specific folder outside of the project.
I am also using the gem rails/cache_digests for automatic expiration.
In a certain page I'm doing fragment caching without setting time expiration.
When a fragment has expired, I see the new fragment created in the cache folder, but I also see the expired fragment as well. How it will be deleted from the cache folder by the cache management mechanism without doing it manually? If it doesn't get deleted then the cache folder will be bloated with garbage, expired fragments that are not used.
You can try to use this cleanup function to delete all the expired fragments. And you may set up a script to run this command periodically.
You can use ActionController::Caching::Sweeping to expire fragment cache.
See below example:
class ProductSweeper < ActionController::Caching::Sweeper
observe Product
#expire fragment after model update
def after_save
expire_fragment('all_available_products')
end
#expire different cache after controller method modifying state is called.
def after_products_update_some_state
expire_action(:controller => 'products', :action => 'index')
end
#can also use before:
def before_products_update_some_state
#do something before.
end
end
This url is also help you

How do I set the URL for a SitePrism::Page that might have a subdomain?

The infrastructure I'm working with originally handled the URLs the way the Site Prism documentation suggested: the domain was handled by setting Capybara.app_host, and the pages themselves called set_url with a relative path.
It turns out that some pages on the production site have a subdomain, like members.mycompany.com rather than www.mycompany.com. The tests also need to be able to run on test environments with different domains entirely, and in the test environments there are no subdomains at all, even for those pages that do have the subdomain in the production site. So putting the full URL into each SitePrism::Page is not an option.
I believed that the best option was to stop using Capybara.app_host entirely, and create a URL builder that would use the state of the environment (i.e. :test or :production), the relative path to the page, and a flag indicating whether or not the page was part of the production subdomain. Something like:
def get_url(relative_path, subdomain_flag=false)
case Environment.get_environment
when :test
domain = "https://testmachine.localenvironment.com"
when :production
if subdomain_flag
domain = "https://members.mycompany.com"
else
domain = "https://www.mycompany.com"
end
end
return "#{domain}" + "#{relative_path}"
end
I had hoped that I could use get_url in each of my SitePrism::Page objects to generate the full URL without the need for Capybara.app_host, like so:
class LoginPage < SitePrism::Page
set_url get_url("/login")
...
end
class MemberPage < SitePrism::Page
set_url get_url("/mypage", true)
...
end
If the Environment were :test, I'd expect the LoginPage to load https://testmachine.localenvironment.com/login and MemberPage to load https://testmachine.localenvironment.com/mypage. If the Environment were :production, I'd expect LoginPage to load https://www.mycompany.com/login and MemberPage to load https://members.mycompany.com/mypage.
I believe the code in my get_url method does what I think it should do, and I also believe that the Environment object I created is having its state set to the proper environment prior to the pages' #load method being called in the test. Sadly, when I try to load my SitePrism::Page objects, the environment value that gets picked up by get_url is always the default value from the Environment object (which is :test). As a result, it ends up loading the test environment URL even if I'm trying to execute against production.
It feels like the set_url part of each SitePrism::Page object is evaluated before the SitePrism::Page objects are instantiated, and I can't seem to find a way to get my initialization of the Environment to happen prior to it. I'm new to Ruby so I'm hoping I'm just misunderstanding the order or hierarchy that these things are loading in, and that it's not difficult to correct. Can anyone identify what's wrong with my attempt, or, if there is a better way to handle this situation, point me to what that better way is?
Yes, those set_url calls are being evaluated when the class is being defined, in other words, when your file is first required.
The simple solution is to make sure that your Environment configuration is initialised before the page objects are required.
Note that the SitePrism docs say that set_url is only needed when navigating directly to a page:
Note that setting a URL is optional - you only need to set a url if
you want to be able to navigate directly to that page. It makes sense
to set the URL for a page model of a home page or a login page, but
probably not a search results page.
For verifying that you're on a page, you can use a regular expression instead. See https://github.com/natritmeyer/site_prism#verifying-that-a-particular-page-is-displayed for an example of running in multiple environments.

How to change ActionCaching "views/" prefix per request

So we use the same controllers to serve both mobile and desktop views of our site. We also use action caching heavily to cache the html for a page in memcache. I've been trying to figure out a way to globally change the caching prefix for all mobile requests to "views-mobile/" instead of the standard "views/". That way the mobile and and desktop pages will be saved under a different namespace so there are no conflicts in memcache.
We could do this per caches_action method by creating a custom cache_path using the controller variable for is_mobile?, but we'd prefer to do it globally somehow. Any suggestions? I imagine this would require monkey-patching ActionController::Caching but I can't figure out where it generates the "views/" prefix.
I'm sorry, I was Rails nubie, so I don't really understand about your question, but if it right, is this what you mean?
This is on my routes.rb:
scope "/administrator" do
resources :users
end
I changed my users_path 'prefix' to administrator. Sorry if wrong :D
I actually ended up figuring this out myself. Basically ActionController::Base uses a function called fragment_cache_key to generate the cache key for a specific fragment (which is what ActionCaching uses deep down). So you basically override that method and include your own logic for how to generate the prefix. This is how my method override looks:
# Monkey patch fragment_cache_key
def fragment_cache_key(key)
ActiveSupport::Cache.expand_cache_key(key.is_a?(Hash) ? url_for(key).split("://").last : key, mobile_device? ? "views-mobile" : "views")
end
Where mobile_device? is my own function that figures out whether the user is requesting the mobile or desktop version of the site.

Do I need to require original file when overriding controller from Rails Engine?

I'm trying to override an action in a controller defined by a Rails Engine.
It seems like I need to require the original file before reopening the class, like so:
require File.join(RAILS_ROOT, 'vendor/plugins/myplugin/app/controllers/some_controller')
class SomeController
def index
render :text => 'this is my index'
end
end
This makes sense, but that require is pretty ugly. Is there some sort of Rails magic that would allow me to avoid the initial require?
This is a complete guess...
Seems more of a load timing problem. As in, your file is getting loaded before the plug-in. Where is your action located? config/initializers? lib?
I'm not to sure when Rails Engines gets loaded so play around with the location (should work by putting it in lib).
Or, better yet, create your own plug-in with the changes and make sure it loads after the original.
And you probably want something more like:
SomeController.class_eval do
def index
...
end
end

Resources