My Rails application is running on a VM. The VM's performance is just fine with static pages. In fact, I'm running another site using Apache virtual hosting that is just serving up static HTML files and the response is adequate. However, my Rails application that is dynamically generating XML files responds very slowly. In fact, it takes about 10 seconds or so for each XML file. These XML files that Rails generates do not change more than once a day.
What is the best practice to configure these XML files to be cached?
Edit 1:
I should mention that these XML files are not viewed by a browser. They are viewed by mobile applications in the "field." So, unfortunately sending "HTTP/1.0 304 not modified" won't work.
Edit 2:
If it matters, I'm using Phusion Passenger to host my Rails app.
If you're using rails' static page caching and serving through apache, just using an explicit xml extension on the urls would do it.
if you're only serving xml and no html you might also edit the apache conf to default to xml instead of html when looking for cached files.
cache expiry is a rather boring thing to code and test, but since you're seldom regenerating the files, you might just expire the entire cache.
Here's a trimmed selection of files and excerpts from how I handle cache in a small, seldom updated rails site:
In the controllers you want to cache
class XmlThingController < ApplicationController
caches_page :index, :show, :other_actions
In the controllers/actions that modify data that would cause changes to the xmls:
class Admin::SomeCrudController < AppplicationController
cache_sweeper :stupid_master_sweeper, :only => [ :save, :destroy ]
In 'config/environments/production.rb'
config.action_controller.page_cache_directory =
File.join(RAILS_ROOT, 'public', 'cache')
Somehere in your vhost apache conf:
# 1.4. Handle caching
# 1.4.1. prevent direct cache access
RewriteRule ^/cache - [F,L]
# 1.4.2. for index
RewriteCond %{DOCUMENT_ROOT}/cache/index.html -f
RewriteRule ^/?$ /cache/index.html [L]
# 1.4.3. for explicitly specified extensions
RewriteCond %{DOCUMENT_ROOT}/cache%{REQUEST_URI} -f
RewriteRule ^(.*)$ /cache$1 [L]
# 1.4.4. with html extension implied
RewriteCond %{DOCUMENT_ROOT}/cache%{REQUEST_URI}.html -f
RewriteRule ^(.*)$ /cache$1.html [L]
# 1.5. Finally, proxy everything else to mongrel
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://your-website-proxy%{REQUEST_URI} [P,QSA,L]
The dumb sweeper that cleans that entire cache every time it's triggered:
class StupidMasterSweeper < ActiveRecord::Observer
observe Foo, Bar # All models that affect caching here
def after_save(record); end
def after_destroy(record); end
def filter(controller)
# sweep everything.
`cd #{RAILS_ROOT} && RAILS_ENV=#{ENV['RAILS_ENV']} rake cache:clear`
end
end
lib/tasks/cache.rake
namespace :cache do
desc "Remove all cached files"
task :clear do
puts `rm -rf #{RAILS_ROOT}/public/cache/*`
end
end
If you prefer to default the default implied extension to xml, change the extension on the 1.4.2 index rule, and the following:
# 1.4.4. with html extension implied
RewriteCond %{DOCUMENT_ROOT}/cache%{REQUEST_URI}.html -f
RewriteRule ^(.*)$ /cache$1.html [L]
to:
# 1.4.4. with xml extension implied
RewriteCond %{DOCUMENT_ROOT}/cache%{REQUEST_URI}.xml -f
RewriteRule ^(.*)$ /cache$1.xml [L]
Send a "HTTP/1.0 304 not modified" HTTP status code to the client when the XML document is requested.
Related
Inspired by that great article from Paul Arterburn and forced by my client SEO needs, I have setup a Wordpress blog hosted by WPEngine to work inside a subdirectory of a Ruby-on-Rails app hosted by Heroku.
Description of the problem
The problem is that relative URLs doesn't match the blog URL. For example when I create a link like Should be https://www.example.com/blog/, the webpage display the link as https://www.example.com. Not cool.
Strange enough, the rest of the links seems to be fine.
A category: https://www.example.com/blog/categories/some-category
An article: https://www.example.com/blog/some-category/my-great-post
Something else could help to solve that problem. We are using the extension AMPforWP. When we add /amp to the post URL, eg https://www.example.com/blog/some-category/my-great-post/amp it become https://example.wpengine.com/blog/some-category/my-great-post/amp.
Eventually, if I desactivate AMPforWP extension, the URLs (but blog home page) can't be reach, the server return an 500 error. Even if I activate the AMPforWP again.
Here's what I have done so far
Ruby-on-Rails
/config/routes.rb
get '/blog' => redirect("https://www.example.com/blog/")
/config.ru
# https://github.com/waterlink/rack-reverse-proxy
use Rack::ReverseProxy do
reverse_proxy /^\/blog(\/.*)$/, 'http://example.wpengine.com$1', :username => 'example', :password => 'fakepwd', :timeout => 500, :preserve_host => true
end
WPEngine admin
https://my.wpengine.com/installs/example/domains
Wordpress admin
https://www.example.com/blog/wp-admin/options-general.php
.htaccess configuration
.htaccess
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
# BEGIN wtfdivi
# END wtfdivi
I'm stuck... :-(
Any help could be greatly appreciated. Thank you.
I know this question has been a while. I had the same setup, I have a rails application pointing to a WordPress blog as a "folder url" instead of a subdomain. Here is how I've solved it.
First, on reverse proxy I had to disable preserve_host so it would keep the domain on the request and not mess with my rules.
config.middleware.insert(0, Rack::ReverseProxy) do
reverse_proxy_options preserve_host: false
reverse_proxy %r{^\/blog(\/.*)$}, "#{Rails.application.config.blog_url}$1"
end
Then on my Wordpress I've moved the installation to a subfolder (named blog), instead of the root folder and used most of the default configuration of .htaccess as follows:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /blog/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /blog/index.php [L]
</IfModule>
# END WordPress
Hope it still can help.
I am learning about the request class.
I have this url http://localahost/blog/search?year=2013&month=07
When i try print_r($_GET) it returns the array as expected.
When i try print_r($request->getQuery());
It returns an empty object Zend\Stdlib\Parameters Object ( [storage:ArrayObject:private] => Array ( ) )
So echo $request->getQuery()->year; returns nothing...
My .htaccess (if needed)
RewriteEngine On
# The following rule tells Apache that if the requested filename
# exists, simply serve it.
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
# The following rewrites all other queries to index.php. The
# condition ensures that if you are using Apache aliases to do
# mass virtual hosting, the base path will be prepended to
# allow proper resolution of the index.php file; it will work
# in non-aliased environments as well, providing a safe, one-size
# fits all solution.
RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L]
WHat you are doing as Mentioned in your Comments was that you are Doing
$request= new $request();
What you need to know is that when you extend a class with AbstractActionController you dont need to do $request= new $request(). AbstractActionController provides you
getRequest()
from which you can fetch request and its data.
I unzip and rename wp-config-sample.php => wp-config.php and conffig it.
it is exactly my file (i have no edit)
// Heroku Postgres settings
if (isset($_ENV["DATABASE_URL"])) {
$db = parse_url($_ENV["DATABASE_URL"]);
define("DB_NAME", trim($db["path"],"/"));
define("DB_USER", $db["user"]);
define("DB_PASSWORD", $db["pass"]);
define("DB_HOST", $db["host"]);
} else {
die("Cannot determine database settings from DATABASE_URL\n");
}
Then I create .htaccess (app/.htaccess) and config(i have no edit):
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /blog/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /blog/index.php [L]
</IfModule>
Then I upload it to blog folder on heroku. And try install but it always return eror 404 (I see logs heroku) my link to install:
http://mywebsite.heroku.com/blog/wp-admin/install.php
ActionController::RoutingError (No route matches "/blog/wp-admin/install.php
Please help me install this.
Thanks so much
You can't do this - but not due to Heroku not having PHP - because it does. The Cedar stack added support for PHP Facebook applications but you are able to run Wordpress on them. See http://tjstein.com/2011/09/running-wordpress-on-heroku-and-amazon-rds/
HOWEVER You cannot mix languages in the same Heroku application, eg Rails and PHP - they would need to exist as separate Heroku applications. When the application slug is compiled the language is detected at that point.
I have made an tested an application on my computer and all is working fine (I used only the dev environment via the frontend_dev.php page).
When I deploy this application on the test server, I have the error 400 Bad Request below:
Bad Request
Your browser sent a request that this server could not understand.
I accessed to the website with the normal URL.
I'm using symfony 1.4 with doctrine (no others plugins are involved), wamp 2 (php 5.3, apache 2.0.59).
If I try to access the application with the dev environment, it works.
Try checking if the no_script property on your application setting.yml file. If should be set to False, clear cache and try again
Thank you very much Guiman. You have leaded me to the answer.
The no_script_name property wasn't the origin of the problem. Instead, I have my .htaccess in the web directory which was badly generated (I swear on my pet's head that I haven't edited this file before). Below is the file generated by symfony (the bold attribute isn't working within the code one, look at the last line):
Options +FollowSymLinks +ExecCGI
<IfModule mod_rewrite.c>
RewriteEngine On
# uncomment the following line, if you are having trouble
# getting no_script_name to work
#RewriteBase /
# we skip all files with .something
#RewriteCond %{REQUEST_URI} \..+$
#RewriteCond %{REQUEST_URI} !\.html$
#RewriteRule .* - [L]
# we check if the .html version is here (caching)
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
# no, so we redirect to our front web controller
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
And this is the updated one (again, look at the last line):
Options +FollowSymLinks +ExecCGI
<IfModule mod_rewrite.c>
RewriteEngine On
# uncomment the following line, if you are having trouble
# getting no_script_name to work
#RewriteBase /
# we skip all files with .something
#RewriteCond %{REQUEST_URI} \..+$
#RewriteCond %{REQUEST_URI} !\.html$
#RewriteRule .* - [L]
# we check if the .html version is here (caching)
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
# no, so we redirect to our front web controller
RewriteRule ^(.*)$ **/myApp/index.php** [QSA,L]
</IfModule>
I don't know what happened but I will check on the symfony website I there are similar issues.
The goal: running a Rails application on Mongrels, allowing access through Apache after doing basic HTTP Authentication
The problem: reading the supplied username from within Rails
Apache:
<Proxy balancer://mongrel_cluster>
BalancerMember http://127.0.0.1:4001
# ...
Order deny,allow
Deny from all
AuthType Basic
AuthName "<realm>"
AuthUserFile "<users-file>"
AuthGroupFile "<groups-file>"
Require group <group>
Satisfy Any
</Proxy>
RewriteEngine On
# ...
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]
That works just fine, Apache forces the user to authenticate and forwards to Rails if successful. I omitted a few lines for handling static files and such, and triggering authentication for them as well.
The environment variables from Rails' perspective contain the usual entries and additionally HTTP_X_FORWARDED_HOST, HTTP_X_FORWARDED_SERVER and HTTP_X_FORWARDED_FOR. I was unable to pass custom environment variables by adding them to the rewrite rule:
RewriteRule ... [P,QSA,L,E=foo:bar]
Any thoughts?
Try using the RequestHeader directive to put REMOTE_USER in an HTTP header. This seems to have worked for the folks in this thread:
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . - [E=RU:%1]
RequestHeader add X-Forwarded-User %{RU}e