Rails3 not rendering page correctly - ruby-on-rails-3

I am writing a simple Rails3 application running in a sub URL that works well except for one problem. If I do not add a ".html" extension at the end of a URL for the "index" method of any of the controllers, the request returns a blank page. It does not matter which controller I request, the "index" method always returns completely empty, including if I curl the URL. I have an "index.html.erb" file in each of the controllers, with simple but complete HTML, and if I do include the ".html" extension in the URL, everything works fine. Here are some example URLs and their results:
http://my.application.url/appname/pages -- returns a blank page.
http://my.application.url/appname/pages.html -- returns the correct HTML page
http://my.application.url/appname/pages/new -- returns the correct HTML form
http://my.application.url/appname/pages/1 -- returns the correct HTML page
http://my.application.url/appname/pages/1/edit -- returns the correct HTML form
My routes file looks similar to this:
My::Application.routes.draw do
scope "/appname" do
resources :posts
resources :pages
root :to => 'home#index'
end
end
The applicable part of my controller looks similar to this:
class PagesController < ApplicationController
def index
#pages = Page.all
respond_to do |format|
format.html
end
end
...
end
As I said, the index method is the only one that is having this problem. I have tried everything I can think of, including adding My::Application.default_url_options = {:format => "html"} in application.rb (which works except when I need to do a redirect_to from the controller), and I am at a loss. The app is using Thin as an application server proxied behind Apache 1.3 (which I unfortunately cannot change, and this doesn't seem to be an issue anyway because hitting the Thin server directly results in the same problem). Any ideas would be much appreciated.

So, the answer seems to be that if the URL does not specify the .html extension, the application will serve out assets (from the asset pipeline) of the same name as the controller, at least while running in the development environment. Once I removed the [controllername].css.scss and [controllername].js.coffee files (both of which were unused anyway) that were auto-generated when I created the controllers from the assets folder, the application worked correctly. Just for kicks, I tried leaving them in and running rake assets:precompile, but the behavior persisted until the files were actually removed. This still seems counterintuitive, and I am contemplating filing this as a bug.

Related

Removing url scope segment with url helpers

I'm writing an app that makes use of AngularJS, so the app is setup to route all requests to the main home page where angular takes over. All routes are then defined within an api scope which angular uses to retrieve the data. It's setup though, that if the user navigates to a page with a normal URL, then when it redirects to the home page, it maintains that URL which angular then uses to load the correct state.
What I now want to do, is be able to use URL helpers within rails to generate my URL's, but not have the generated URL's include the /api of the scope. Is there any way I can get around this?
routes.rb looks a bit like
scope "/api", shallow_path: "/api" do
... normal stuff here ...
end
And if I try using one of the helpers,
meeting_url(#meeting, subdomain: "test")
the url it generates is
http://test.domain.com/api/meetings/1
Is there a way I can have it strip the /api?
I don't believe there's a built-in way to do it.
But, you're in ruby, so there are plenty of ways to do what you want.
One way to go, since you're in your own app, is do monkey-patch String:
class String
def no_api
self.gsub(/\/api/, '')
end
end
meeting_url(#meeting, subdomain: 'test').no_api #=> http://test.domain.com/meetings/1
If you find that distasteful, you can define a method on ApplicationController or in a helper module:
def no_api(url)
url.gsub(/\/api/, '')
end
etc. etc. etc.

Rails 3.2 Mountable App locale getting duplicated

I am seeing a scenario where my locale parameter is getting duplicated once I step into a mountable app. My app looks like so:
#routes.rb
resources :blogs
scope "(:locale)" do
mount Auth::Engine => '/auth'
end
If I am at a blogs page and look at an auth link it looks like this /en-us/auth/signout which works well, but as soon as I load into any page rendered by the mountable app, for example the profile page /en-us/auth/myprofile', the sign out link now looks like /en-us/auth/signout?locale=en-us
I don't want the querystring getting cluttered, what is causing the app to correctly set the locale parameter and then duplicate it in the querystring?
my bet is that your application controller has something like:
def set_locale
# code here
end
def default_url_options
# code here
end
Since your engine controller inherits from application controller, set_locale may be triggered twice.
Potential Solution: Check if the code is in an engine, then don't trigger locale setting.
This can be done with: self.controller_path().split("/").first == engine_name
I had the same problem. I was setting the default url options on the controller (by redefining default_url_options or by using self.default_url_options=).
The solution was to use Rails.application.routes.default_url_options = instead.

rspec render_views ignores layouts? want to test static cached page does not display flash message

I'm trying to test that "static" pages (they're ERB, but get cached), generated through rails, don't render any stray flash notices left over by the authentication system (Devise) or wherever else.
I've tried writing this controller spec, but it appears that response.body only renders the template, not its layouts?
describe "so that static caching can be used" do
render_views
specify "flash notices are not rendered" do
# edit: the following flash lines don't do anything
# it's not the right flash object, this one is intended for
# inspecting after request not setting before request
flash[:notice] = "flash boo"
flash[:error] = "flash boo"
flash[:alert] = "flash boo"
get :show, :page => 'privacy_policy'
response.body.should have_content('flash boo')
end
end
class StaticPagesController < ApplicationController
layout 'master'
def show
response.headers['Cache-Control'] = "public, max-age=#{6.hours}"
render "static_pages/#{params[:page]}"
end
end
I've tried changing to a layout which does render flash notices, and even inserting the text into the layout template, but can't make the spec fail.
Is there a way to ask rspec to render the template with the appropriate layouts as well?
Is a controller spec the wrong way to try and do this?
It seems out of place, as it's more to do with which layouts are being used, and their contents, but the rendering process starts at the controller, it receives the result, and I can manipulate the flash hash contents before rendering.
Versions:
rails (3.0.10),
rspec-rails (2.6.1),
rspec-core (2.6.4)
Thanks, Nick
Turns out this isn't the right approach. It should be an integration test (cucumber, request spec, etc) as it's testing several layers. That and rails doesn't seem to render the templates inside their layouts at this level.
So in integration test:
Set up a flash message by making a request to a controller which does nothing else (create a dummy controller & routing in your test code), then hit the page of concern and make sure the flash notice isn't rendered.
e.g. https://gist.github.com/1178383
It seems like a long way round but it will cover it.

Render a page as a saved HTML file using Rails 3.0?

I'm building a simple website generator application in Rails 3.0. I'd like a "publish" action in a controller that works just like an ordinary "show" action, but instead, saves a page as an HTML file in the "public" directory instead of displaying it in the browser. That is, I'd like to use the Rails render mechanism to create a file instead of providing an HTTP response.
What's the best way to do this?
Should I simply add caches_page :publish to the controller?
Or use render_to_string and File.new?
You can use render_to_string method: http://apidock.com/rails/AbstractController/Rendering/render_to_string
You still need to respond from the controller though. Maybe redirect to the page you just saved?
I would go with page caching.
Then if you have editable content, the pages should be automatically generated. You could then write a system task which bundles them up as a web site.
see (whatever)/actionpack/lib/action_controller/caching/pages.rb for instructions.
I found that page caching using caches_page won't work for me because there is no way to show a notification or redirect to another page after caching the page. The method render_to_string (suggested by #Grocery) is the way to go. Here's the example controller code:
def publish
#article = Article.find(params[:id])
html = render_to_string(:template => "articles/template.html.haml", :layout => 'article' )
FileUtils.makedirs("#{Rails.root}/public/articles/") unless File.exists?("#{Rails.root}/public/articles/")
File.open("#{Rails.root}/public/articles/#{#article.filename}.html", 'w') {|f| f.write(html) }
respond_to do |format|
format.html # publish.html.erb
end
end

Force absolute URIs for a specific controller action

I've got a controller action that generates a template for an online credit card payment gateway (Ogone). I need to force all URIs (image links in the layout, stylesheets, javascripts ...) to be absolute in this case, since the page will be filled up and rendered by the payment gateway server itself.
What is the "rails 3 way" of doing that?
Thanks!
I finally solved my problem completely outside of rails, with the use of wget, with option -k, which converts all relative links to absolute links. It my controller, it looks like:
def action_with_relative_links
end
def action_with_absolute_links
render :text => convert_to_absolute_links(:action_with_relative_links)
end
def convert_to_absolute_links(action_param)
`wget -q -k -O/tmp/absolute_links.html #{url_for :action => action_param}`
`cat /tmp/absolute_links.txt`
end
There is still one little thing to correct in this code: the problem that may arise in high concurrency, because of the use of a temporary filesystem file.
I wish there was a way to avoid that hack, and do everything in rails, but I'm pretty happy with the result, and it permits me to keep all my views and layout files unchanged.
I hope it can help someone!