Redirecting Folders in Middleman's config.rb - ruby-on-rails

I'm using the static site generator Middleman to build my site. We currently have landing pages that we proxy via config.rb as such:
# landing page template directories to redirect
landingpage_seo_templates = Dir['source/landingpages/seo/*.erb']
# point all landingpage/seo templates to the root
landingpage_seo_templates.map! do |tpl_name|
tpl_name = File.basename(tpl_name).gsub(/.erb$/, '')
proxy "/#{tpl_name}/index.html", "/landingpages/seo/#{tpl_name}.html", :ignore => true
end
This points all of the files in a directory from /landingpages/seo/{filename}.erb to the /{filename}.erb when the site is built. However, this doesn't work for sub-folders.
My question is how would I modify this script to render the sub-folders. For examples I would like files in /landingpages/seo/foo/{filename}.erb to render to /foo/{filename}.erb
I know how to do this via .htaccess, however I'd like to learn how to do this via config.rb.
Thank you in advance.

If you modify your file pattern ...
landingpage_seo_templates = Dir['source/landingpages/seo/**/*.erb']
... you should get all erb templates in the seo tree.
You then need to modify the tpl_name computation (there probably is a smarter/shorter way for that):
# point all landingpage/seo templates to the root
landingpage_seo_templates.map! do |tpl_name|
tpl_name = tpl_name.gsub(/.erb$/, '')
tpl_name = tpl_name.gsub(/source\/landingpages\/seo\//, '')
proxy "/#{tpl_name}/index.html", "/landingpages/seo/#{tpl_name}.html", :ignore => true
end

Related

How to serve static files in Rails from a mounted path

I am trying to develop a gem to be used in Rails applications that includes serving static files (html, js, and css) at a mounted location. Using the gem's UI will be accomplished by adding the following to config/routes.rb
mount MyGem::UI.new, at: "/foo"
I have this almost working using Rack::Static, but am not attached to this solution if there is a better one.
module MyGem
module_function
def root
#root ||= Pathname(__dir__).expand_path
end
end
module MyGem
class UI
def call(env)
static_app.call(env)
end
def static_app
Rack::Static.new(nil, static_options)
end
def static_options
{urls: [""], root: asset_path, index: 'index.html'}
end
def asset_path
#root ||= MyGem.root.join("assets")
end
end
end
The files at MyGem.root/assets can be reduces to a single html file that links to a single css file in the same location using href="./index.css". (In reality they will be a React app built with homepage: "./" in package.json using create-react-app to produce ./ relative links to all assets.) I have tested this setup using both the dummy and the full-fledge React app.
This setup works if and only if I go to localhost:3000/foo/ with the trailing slash. However, if I navigate to localhost:3000/foo without the trailing slash, I successfully get the index.html page, but all of its links are broken, returning 404 not found:
GET http://localhost:3000/index.css net::ERR_ABORTED 404 (Not Found)
How can I avoid this and robustly server my static content at the mounted location, "/foo"? It's halfway acceptable as a pilot to just require the trailing slash, but is a bit dodgy to leave in a published gem.
I am open to solutions involving alternate rails routes configurations, different ways to serve the static content (contingent on being easily describable to gem users), and different ways to build the static content, and anything else.

How to override public folder path in Rails 4?

I would like to use a different public folder from a parent directory called client which contains the entire AngularJS app. Essentially I want to tell Rails to load AngularJS app and the only job that Rails has to do is serve JSON.
Is that possible in Ruby on Rails?
As others have mentioned, it may or may not be a great idea to override the existing paths['public'] folder. But you can do the following safely in somewhere like application.rb:
Rails.application.config.middleware.insert_after(
ActionDispatch::Static,
ActionDispatch::Static,
Rails.root.join("client").to_s,
Rails.application.config.static_cache_control
)
The public folder is exposed to the web server through the Rack middleware ActionDispatch::Static. There's nothing else special about it, and the above code simply adds another instance of the middleware that points to the directory client. So in the above case, the browser would be able to access everything in public as well as client.
Just had to do it myself for an Angular app.
Put this in your application.rb:
config.serve_static_files = true
paths['public'] = File.join 'client', 'app'
Or if you still use asset pipeline (config.assets.enabled = true):
paths['public/javascripts'] = File.join 'client', 'app', 'scripts'
paths['public/stylesheets'] = File.join 'client', 'app', 'styles'
Would be interesting to know if there are any consequences with the second bit as my front-end is served completely separately thus I keep asset pipeline switched off and use grunt instead.
You can define another path like
# config/application.rb
paths['my_website'] = 'website'
Then you can use this path in your routes like
# routes.rb
get '/my_website', to: redirect('my_website/index.html')

Rendering Partials within the Asset Pipeline in Rails

Does anyone know how to render a partial (or at least include another file) within a asset file in rails? I have a templates/ folder setup (which contains static HTML files) and there bits and pieces within these files that I would like to abstract and share between other template files.
The render method doesn't work in any asset pipeline files. I'm sure I can include it somehow by finding the correct module, but I'm not sure if this would work since the render module itself may rely on other modules, methods, variables.
Any ideas on how to do this? Or if its possible?
I've come up with my own solution.
You create a helper file in the lib folder and call it assets_helper.rb. The code within the asset_helper is as follows:
def partial(name, args = {}, dir = 'app/assets/templates')
require 'ostruct'
namespace = OpenStruct.new(args)
name += '.html'
[name + '.erb', name].each do |n|
n = File.join(dir, n)
next unless File.exist?(n)
tpl = ERB.new(File.new(n).read)
compiled = tpl.result(namespace.instance_eval { binding })
return compiled
end
end
Then you include that file at the top of each asset file that you wish to use it in. Inside of the file you can use the partial command like so.
<% require './lib/asset_helper.rb' %>
<!--- some HTML template --->
<%= partial('page/_partial', :var1 => true, :var2 => false) %>
<---- some other page --->
This works. But the only issue is that the Rails 3.1 will cache anything that's in the assets folder. So if you edit a partial you will need to update the root file that it's inside of so that the cache gets cleared for that file.

How can I display an image whose path is outside my Ruby on Rails project directory using rails 3?

how to display the image, which stored outside from the project directory?
Is there a simple way to do it?
I see two ways :
On top of your rails server, in production and sometimes in dev, you have to use a web server like apache or nginx. With these, you can serve files from other directories for specific URL. E.G. you can make http://yourapp.com/images/ serving files from a specific dir. In rails, display the image with a traditionnal image_tag
Example with Nginx :
# Find the right `server` section which you currently use to serve your rails app
server {
listen 80;
# Add this
location /images {
root /var/www/my/specific/folder;
}
location / {
#...
#... Here you should already some code to proxy to your rails server
}
}
With that, when you access to `yourserver.com/images`, nginx serve your specific folder and not your rails app. Then in your app view :
<%= image_tag 'http://yourserver.com/images/my_pic.jpg' %>
If you can't access your server settings, you can serve an image file from a controller action with send_file
In a controller :
class ImagesController < ApplicationController
def show
send_file File.join('/var/www/my/specific/folder',params[:name]), :disposition => 'inline'
end
end
In config/routes.rb
match '/images/:name' => 'images#show', :as => :custom_image
Then when you access this action (via the route you defined in config/routes.rb), you have the image. So in your view you do a traditionnal image_tag with this URL :
<%= image_tag custom_image_path( 'my_pic.jpg' ) %>
OR
<%= image_tag custom_image_url( 'my_pic.jpg' ) %>
If it's stored outside of the Rails app directory, then it does not belong to asset pipeline and you can simply link to it:
<%= image_tag("http://example.com/some_file.jpg") %>
Obviously it must be accessible through HTTP (you need nginx or Apache server installed).
This is probably bad idea and will lead to a bunch of issues. Some security, some functionality, but most of the effects I actually don't know.
I do know, from experience, that whenever you go against the rails conventions for what and where stuff is, it's a slippery slope of things breaking, best avoided.
Create a solution using the framework provided.
Note this functionality can also be affected a bit if you are using rails 3.1+ as opposed to <= 3.0 due to asset compilation which copies js, css and images into public.

Render static files in /doc in Rails

So far I have in config/routes.rb:
match 'doc/:path' => 'doc#show'
And in app/controllers/doc_controller.rb:
class DocController < ApplicationController
layout false
def show
render File.join( RAILS_ROOT, 'doc', params[:path] )
end
end
This works find for index.html and other .html files. But it doesn't serve up .css and .js files. It also doesn't serve nested files and directories such as /doc/metrics/output/index.html
How can I get Rails to serve up all static files in /doc but without simply putting a link to them in /public (so that I can autheticate the user in the controller first)?
I would recommend not serving the files through Rails at all. Serve them through your server (Nginx, Apache). You can use the X-Accel-Redirect and the X-Sendfile headers to tell Nginx and Apache to send the static file instead. The benefit of this approach is that you can still authenticate a user before allowing them access to the file. Here's the Nginx tutorial:
http://ablogaboutcode.com/2010/11/19/serving-static-files-passenger-nginx/
Another option is to setup your routes like this:
match 'doc' => 'doc#show'
And pass your path as a parameter so you don't have to do nested URL matching in your routes, or handle special cases (.css, .js, .html, ...)
/doc?path=/path/to/my/document.css

Resources