I'm using caching in a rails app, but there are times where I'd like to be able to turn off caching for a specific request or regenerate the cached data (in production). I'd want to do this for debugging but also just to see what the performance difference is between the two.
Is there a way to turn off caching (with something like &cache=false) across the board without adding things like this throughout my code:
<% cache(x) unless params[:cache] == "false" do %>
Is there a way to tell rails to invalidate all of its cached elements as it renders the page, regenerating them? This would work, but again, I'd have to do it everywhere:
<% Rails.cache.delete <key> if params[:clear_cache] == "true" %>
or is there a good reason why I should just never do this.
You could always write that up as a method that you use instead of "cache"
def my_cache(x)
return x if params[:cache].blank? || params[:cache] == true
cache(x)
end
It'd be a little less messy in your views...
Alternatively, you might (I'm guessing) be able to play with ActionController::Base 's cacheing internals... but it'd be meta-hacking on rails' base code.
Related
I have a multi-step form where the user fills out info on several different pages. In conventional rails, you keep each resource separate in its own controller and you use the REST actions to manipulate the data.
In the conventional system I would have 3-5 different controllers (some steps are optional) for a single multi-step form. There's no real sense of "order" in the controllers if I do it the conventional way. A new developer coming on to the project has to learn what steps map to what steps and so forth.
On the other hand, I have thought about breaking convention and having a single controller that organizes the entire multi-step form. This controller would be full of methods like:
def personal_info
# code...
end
def person_info_update
# code...
end
def residence_info
# code...
end
def residence_info_update
# code...
end
# many more coupled methods like the above...
This single controller will get fairly long, but it's essentially a bunch of coupled methods: one for showing the step (form) and the other for updating and redirecting to the next step.
This would be breaking rails convention and I would have to setup my own routing.
But I'm curious how others have solved this problem? I know both CAN work, but I would like to know which is easier to maintain and code with in the long run.
A resource does not equal a page. I suspect that both ways would break a constraint on REST.
All of your interests have been with the View domain, which resides in your browser. If you want to display a single form in multiple parts you should do so using HTML, CSS etc.
Otherwise your just creating temporary storage on your servers for the forms progress.
I did something like this with https://github.com/pluginaweek/state_machine
The idea was to have one state per step of the form and simply render a different form partial depending on which state the actual resource has. The above gem let's you specify validations and callbacks for each states.
Like this, you can use the standard REST controller actions.
Moving over from django / python, I am having a little trouble getting the rails logger to log all the information I want. I am wondering how/if the following can be achieved:
Having in the log format(ter) include the specific file, function name and line where the logging statement itself was found. Essentially the equivalent of LOG_MSG_FORMAT = '%(asctime)s %(levelname)s %(filename)s:%(funcName)s(%(lineno)d) : %(message)s' in python logger?
Being able to log all requests, via something similar to a django request logging middleware. Particularly, being able to log the username (if logged in) of every request.
Am I missing something obvious? or does this require (lots of) custom code?
I just found this railtie gem that might help although I imagine it will take some "custom code" to append username to logs. See the Readme section on logging specific controllers and models.
logging-rails railtie
I don't know about getting the file, function, and line number, but it's pretty easy to log from application_controller:
class ApplicationController < ActionController::Base
before_filter :log_user
def log_user
if current_user
Rails.logger.info "Processing Request for #{current_user.name}"
end
end
end
Just to add a quick note in case this is useful for someone:
The lograge gem makes rails logs much similar to django's, plus allows very neat customization, adding parameters such as remote ip address, current_user etc.
It also reduces verbosity of rendered layouts, which I anyway found unnecessary for production. It also plays nicely with logging-rails railtie mentioned by #lukewendling.
Sadly, I still couldn't find anything that shows the file/function/line number like you can easily do with django, but I guess that's just too much to ask.
I've got a product page. The show action has the following code:
def show
...
LiveView.add_live_view(#product, request)
...
end
In this same controller, if I have:
caches_action :show, :cache_path => (proc do
product_path(params[:id], :user_id => user_signed_in? ? current_user.id : nil)
end)
I'm trying to display real-time views, by grabbing the IP address from request. So, I need to keep track of every view that hits the page. However, if the page is already cached, it will never trigger the LiveView.add_live_view(#product, request) method.
The question is. Should I be caching this action? If so, how should it be done? Or should I forget about caching for this method?
Should I think of a different caching approach? Any suggestions?
I am not sure if caching at the application level is the right solution. I suggest looking at mod_cache which caches the response at the apache layer. (If you are running apache with passenger).
Finally, don't forget about this rule. Never optimize unless you have to. What I mean is, test your application first. Doesn't suffer performance loss if you don't cache. Do you still need to cache everything? Do some code analysis and maybe you can use a better algorithm.
Edit, also look at HTTP status code 304. If the user refreshes the page, and you can convey that nothing has changed then just return 304.
I have a routing like that:
namespace :folio do
resources :portfolios do
resources :portfolio_items do
resources :images
end
end
end
Now please donĀ“t flame me because of the deep stacking. This is a mongo db persisted tree like object and those levels are all persisted in the root object.
What puzzles me is the fact that the generated routings read something like
folio_portfolio_portfolio_item
But when I ask for a url from urlhelper
url_for [#portfolio, #portfolio_item]
I get a nice exception telling me
undefined method `hash_for_folio_portfolio_folio_portfolio_item_path' for #<Module:0x0000000492fc30>
See the second "folio" in there? Any idea how I can get rid of that? Providing an :url => is not an option, unfortunately, because that would triplicate my form views and before that I'd rather ditch the namespace altogether. But unwillingly so: this is a rails engine and I would want to avoid clashes.
So, in other words...
I want
= form_for [#portfolio, #portfolio_item] do |form|
to "just" work :). Is this too much to ask?
Observation
a routing like that brings me a bit forward:
resources :folio_portfolio_items, :controller=>Folio::PortfolioItemsController do
while ugly as hell it generates good urls. Problem is, when I want to to visit one of them I get
ActionController::RoutingError (uninitialized constant Folio::Folio):
Whatever this means...
As a sidenote I think it is very odd that this happens at all. I think my mapping controllers to domains is the expected one...
I created a sample app that illustrates this on https://github.com/janlimpens/testroutes
Do you have to add code to your Rails app to use memcache? I've added config.cache_store = :dalli_store to my production environment and Rails.cache.write('color', 'red') works.
I haven't made any modifications to my models, views, or controllers. When I create and save an object, for example
user = User.new
user.name = 'John Doe'
user.email = 'john#doe.com'
user.save
it is going straight to the database and not going to memcache. I was hoping activerecord would use memcache automatically if configured for it. Is that not the case? Any good articles on rewriting your models to use Rails.cache (or should this be something done in the controller)?
config.cache_store is only going to be used for configuring the store used in writing and retrieving cache. This is completely separate from your model data storage.
http://guides.rubyonrails.org/caching_with_rails.html
Are you trying to substitute an ActiveRecord database like MySQL with memcached? Writing to memcached when you create a new record, instead of writing to a database?
UPDATE BASED ON YOUR COMMENT
cache_money is doing the write_through using activerecord callbacks.
http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
Look at the line 15-17 and you can see where they call the after callbacks:
https://github.com/nkallen/cache-money/blob/master/lib/cash/write_through.rb
You could accomplish what you need in the same manner. Just code a custom method and make it available to your models. Then call the method with after_create, after_update, after_destroy in the model. If you want to make it happen to all models, you could probably do this in an initializer:
#UNTESTED, but should be close
ActiveRecord::Base.descendants.each do |model|
model.class_eval do
after_create :your_cache_method
#... other callbacks
end
end
You could then code a module with your_cache_method in it and include it in ActiveRecord::Base, so it would be available to all models