Best ruby-on-rails questions in September 2011

rails 3.1.0 ActionView::Template::Errror (application.css isn't precompiled)

13 votes

I made a basic rails app with a simple pages controller with an index function and when I load the page I get:

ActionView::Template::Error (application.css isn't precompiled):
    2: <html>
    3: <head>
    4:   <title>Demo</title>
    5:   <%= stylesheet_link_tag    "application" %>
    6:   <%= javascript_include_tag "application" %>
    7:   <%= csrf_meta_tags %>
    8: </head>
  app/views/layouts/application.html.erb:5:in `_app_views_layouts_application_html_erb__43625033_88530400'

Gemfile

source 'http://rubygems.org'

gem 'rails', '3.1.0'

# Bundle edge Rails instead:
# gem 'rails',     :git => 'git://github.com/rails/rails.git'

gem 'sqlite3'

gem 'execjs'
gem 'therubyracer'

# Gems used only for assets and not required
# in production environments by default.
group :assets do
  gem 'sass-rails', "  ~> 3.1.0"
  gem 'coffee-rails', "~> 3.1.0"
  gem 'uglifier'
end

gem 'jquery-rails'

# Use unicorn as the web server
# gem 'unicorn'

# Deploy with Capistrano
# gem 'capistrano'

# To use debugger
# gem 'ruby-debug19', :require => 'ruby-debug'

group :test do
  # Pretty printed test output
  gem 'turn', :require => false
end

By default Rails assumes that you have your files precompiled in the production environment, if you want use live compiling (compile your assets during runtime) in production you must set the config.assets.compile to true. You can use this option to fallback to Sprockets when you are using precompiled assets but there are any missing precompiled files. If config.assets.compile option is set to false and there are missing precompiled files you will get an “AssetNoPrecompiledError” indicating the name of the missing file.

How to send the browser to an error page if part of the response has been sent (chunked)

9 votes

This is typical scenario: a page is evaluated, and there's a buffer - once the buffer is full, the part of the page that is evaluated is sent to the browser. This uses the HTTP 1.1 chunked encoding.

However, an error can occur in one of the chunks (after the first one is already sent). In that case:

  • you can't redirect (send a Location header), because the headers and the response status were already sent
  • you can't do server-side redirect (forward), because the new page will have to be rendered after the part that is already sent - it will look ugly for sure.

So what should you do in this case? I asked a question whether you can send a Location header in the chunked trailer, but this is low-level http and the abstraction of languages may not allow it, even if it is possible (and it is likely not to be supported across browsers)

Another option is to send a <script>window.href.location="errorPage"</script> and thus force the client to redirect, but that's ugly. Plus you have to put </script> to close any potential unclosed <script> tag in the partial page.

(I'm tagging major web languages/frameworks, because this is an universal issue)

You cannot redirect from the server in a chunked encoding because the headers have already been sent. The only way to perform a redirect is to send a <script> tag from the server and perform a client side redirect. Just out of curiosity are you trying to implement a COMET server? If this is the case HTML5 WebSockets seem better way (if the browsers you are targeting support them of course) compared to the hidden iframe technique.

How to upgrade a Rails 3.0 app to Rails 3.1?

8 votes

I have a Rails 3.0 app (technically 3.0.7) which I would like to upgrade to Rails 3.1 to make use of the new asset pipeline and other fancy new features. What is the best approach to doing this? Should I use the rails new generator, then copy everything from my old app over to the new one? What about version control? I already have my old app using Git.

Just upgraded one of my apps from 3.0.9 to 3.1.0, here's my approach, your mileage might vary:

Edit Gemfile, change Rails gem version

gem 'rails', '3.1.0'

Also adds new gems introduced in 3.1.0

group :assets do
  gem 'sass-rails', "~> 3.1.0"
  gem 'coffee-rails', "~> 3.1.0"
  gem 'uglifier'
end
gem 'jquery-rails'

run bundle update rails

Then run rake rails:update and resolve conflicts.

Move your css/javascript/images etc to app/assets folder, make sure there's an application.js and an application.css file (you might want to take a look at those two from newly created 3.1.0 projects)

Include css/javascript links in your layout file like this

<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "application" %>

How to universally skip database touches when precompiling assets on Heroku

7 votes

I'm deploying a Rails 3.1 app to Heroku's Cedar stack. With Heroku Cedar and Rails 3.1, you can compile the assets yourself locally, let Heroku compile them when you push (during "slug compilation"), or have them be compiled just-in-time while the app is running. I want to do the middle option, letting Heroku precompile the assets.

When Heroku runs the assets:precompile task, it errors with "could not connect to server" because the app is trying to connect to the database but no database is available at that stage of slug compilation. The lack of database connection is expected and unavoidable at this point. I'm looking for a way to move past it, because a database connection isn't crucial to asset precompilation.

The part of my app that's trying to connect to the database is Devise. There's a devise_for :users line in routes.rb that wants to look at the User model.

I could just write a rake task that stubs out devise_for and make it a prereq of assets:precompile. I think that would solve my problem, but I'm looking for a more universal solution that I could use on any Rails 3.1 app with this problem on Heroku.

Is there anything out there, or can you conceive of anything that silences database connection errors while still running the app enough to have route and asset path generation?

Obviously if an app needs to read/write data during startup, we can't stub that, but can we fake every ActiveRecord model automatically?

Not quite a universal stubbing but devise has added a check now to fix this particular problem . See the issue and fix on Github. By providing a RAILS_ASSETS_PRECOMPILE environment config devise should skip building the routes

Invalid date format specification in gemspec

6 votes

I am getting the following error when I try to use gems in windows, and I also referred to stackoverflow post here and updated rubygems and rails. But nothing could solve the problem.

The following is the complete error,

    D:\>gem env
Invalid gemspec in [D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8/specifications
/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00
.000000000Z"
Invalid gemspec in [D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8/specifications
/execjs-1.2.4.gemspec]: invalid date format in specification: "2011-08-03 00:00:
00.000000000Z"
Invalid gemspec in [D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8/specifications
/temple-0.3.3.gemspec]: invalid date format in specification: "2011-08-26 00:00:
00.000000000Z"
Invalid gemspec in [D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8/specifications
/guard-0.6.3.gemspec]: invalid date format in specification: "2011-09-01 00:00:0
0.000000000Z"
Invalid gemspec in [D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8/specifications
/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09
-01 00:00:00.000000000Z"
Invalid gemspec in [D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8/specifications
/rack-cache-1.0.3.gemspec]: invalid date format in specification: "2011-08-27 00
:00:00.000000000Z"
Invalid gemspec in [D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8/specifications
/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00
.000000000Z"
Invalid gemspec in [D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8/specifications
/execjs-1.2.4.gemspec]: invalid date format in specification: "2011-08-03 00:00:
00.000000000Z"
Invalid gemspec in [D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8/specifications
/temple-0.3.3.gemspec]: invalid date format in specification: "2011-08-26 00:00:
00.000000000Z"
Invalid gemspec in [D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8/specifications
/guard-0.6.3.gemspec]: invalid date format in specification: "2011-09-01 00:00:0
0.000000000Z"
Invalid gemspec in [D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8/specifications
/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09
-01 00:00:00.000000000Z"
Invalid gemspec in [D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8/specifications
/rack-cache-1.0.3.gemspec]: invalid date format in specification: "2011-08-27 00
:00:00.000000000Z"
RubyGems Environment:
  - RUBYGEMS VERSION: 1.7.2
  - RUBY VERSION: 1.8.7 (2011-06-30 patchlevel 352) [i386-mingw32]
  - INSTALLATION DIRECTORY: D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8
  - RUBY EXECUTABLE: D:/RailsInstaller/Ruby1.8.7/bin/ruby.exe
  - EXECUTABLE DIRECTORY: D:/RailsInstaller/Ruby1.8.7/bin
  - RUBYGEMS PLATFORMS:
    - ruby
    - x86-mingw32
  - GEM PATHS:
     - D:/RailsInstaller/Ruby1.8.7/lib/ruby/gems/1.8
     - C:/Documents and Settings/jeygokul/.gem/ruby/1.8
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :benchmark => false
     - :backtrace => false
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - http://rubygems.org/

I have fixed this issue by upgrading my RubyGems to 1.8.10 with

gem update --system

Multiple models in the same form in Rails 3.1?

5 votes

I am using Rails 3.1 and am working on a discussion forum. I have a model called Topic, each of which has many Posts. When the user makes a new topic, they should also make the first Post as well. However, I am not sure how I can do this in the same form. Here is my code:

<%= form_for @topic do |f| %>
<p>
    <%= f.label :title, "Title" %><br />
    <%= f.text_field :title %>
</p>

<%= f.fields_for :post do |ff| %>
    <p>
        <%= ff.label :body, "Body" %><br />
        <%= ff.text_area :body %>
    </p>
<% end %>

<p>
    <%= f.submit "Create Topic" %>
</p>
<% end %>

class Topic < ActiveRecord::Base
  has_many :posts, :dependent => :destroy
  accepts_nested_attributes_for :posts
  validates_presence_of :title
end


class Post < ActiveRecord::Base
  belongs_to :topic
  validates_presence_of :body
end

... but this doesn't seem to be working. Any ideas?

Thanks!

@Pablo's answer seems to have everything you need. But to be more specific...

First change this line in your view from

<%= f.fields_for :post do |ff| %>

to this

<%= f.fields_for :posts do |ff| %>  # :posts instead of :post

Then in your Topic controller add this

def new
  @topic = Topic.new
  @topic.posts.build
end

That should get you going.

Can Heroku be configured to do a true seamless deployment?

5 votes

Our team has been very interested in continuous deployment recently, but we've run into a little bit of a roadblock in regards to how to actually get code deployed on Heroku - it seems inevitable that there needs to be some amount of downtime to do a code push to Heroku.

In a traditional environment, code deployment would probably look something like this:

  1. Push the code up to a staging directory somewhere (old code is still live)
  2. Run migrations against the database (more often than not, it's safer to run migrations beforehand, and the few that will break the code can be guarded against)
  3. Take half (or some percentage of servers) out of the load balancer.
  4. Deploy code to those servers.
  5. If possible, run some sort of automated smoke test / exercise the servers so they're "hot"
  6. Switch which servers are in and out of the load balancer
  7. Rinse and repeat.

With Heroku, I have very little control over two critical steps:

  • I can't run database migrations first. One way I've considered to get around this is to keep database migrations branched seperately, and push those to heroku first - which while painful, would solve the problem - but only exacerbate...
  • Dyno spin-up time can take a fairly long time - obviously, this is more the fault of Rails than of Heroku, but the key problem is that I can't do something like the load balancer shuffle above to ensure that my app is ready and loaded before a newly deployed server is put back into the load balancer. Instead, I pretty much have no choice but to give users a 10-15 second load screen and hope for the best (and do that TWICE if I use the database deployment strategy from above)

We do use the maintenance screen currently, but it's not going to be a scalable solution if we move to full continous deployment (we'd probably have about 10-20 deployments a day, and 10-20 * 30 seconds of maintenance screen starts to add up)

Has anyone run into similar issues? How did you address them? Any great case studies / success stories for true continuous deployment on heroku?

On Heroku we'll issue a SIGTERM to your dyno(s) at restart. After a short while if the process(es) don't stop they will be killed. This should allow you enough grace time for a seamless restart when you're not running migrations.

You can always push code to a staging app that's pointed at your production DB and run migrations from there. Pedro wrote a nice blog post on running zero downtime migrations that should help too: http://pedro.herokuapp.com/past/2011/7/13/rails_migrations_with_no_downtime/

Hope this helps some.

What is the best way to go about upgrading a rails app to support Facebook SSL?

5 votes

With the upcoming SSL migration at Facebook on 1 October, all apps will have to support connections over HTTPS and for that you'll need an SSL certificate.

  • Is there a run-down anywhere of how a person should patch an app?
  • Will you have to use Apache and Passenger, xginx or other server?
  • Are there any free trusted certificates?

Is there a run-down anywhere of how a person should patch an app?

Not really. Why? Because it all depends on what version of rails you are running.

For Rails 2.x, I've read/heard of techniques including:

  1. ModRewrite - use the webserver's ability to detect and rewrite HTTP to HTTPS. This technique is more general and could apply to a whole host of technologies, not just rails (python, java or even .net).
  2. Use ssl_requirement gem - this allows you to declaratively add instructions in your controllers to redirect to https if the protocol is http (https://github.com/retr0h/ssl_requirement). Although simple, your ruby app will have to handle the request, and I'm not sure how quick ssl_requirement is.
  3. Use rack middleware (rack-ssl, rack-ssl-enforcer gem) - this patches the request handling of rails, so that the redirect is handled well before it hits any controller. This is configureable too (you can match based on path etc) and is probably better than option 2.

For Rails 3.1, it's backed into the framework. You just need to do this:

# config/application.rb
module MyApp
  class Application < Rails::Application
    config.force_ssl = true
  end
end

Will you have to use Apache and Passenger?

Not necessarily. There are other options like NGinx and Passenger. But in general, yes you will probably need a proper web server sitting in front, handling the SSL portion of the request.

Typically, a web server is required to sit in front of your app. It needs to be configured to handle SSL traffic, and direct the requests to your app (http and https). Here you can use Apache or NGinx.

Passenger sits as a "plugin" in Apache/NGinx to handle requests through to your application. At this point, SSL isn't usually a concern (ie. the request is now unencrypted.). What your app has to then do, is handle the request. Here's where you detect if the protocol is http or https and instruct the browser to redirect if necessary.

Are there any free trusted certificates?

No. Trusted certs are usually signed by a Certificate Authority. These guys typically have to check that your domain and the company or individual that holds the domain are genuine and real. To do that, you pay money. There are plenty of providers out there that can issue you an SSL cert for around $100 USD. Some more, some less.

Certs are typically locked to a domain. And you pay more for wildcard domain matches (e.g. *.myapp.com). If you're after a cert for development, you can generate a self signed certificate.

I've written an article showing you how to get HTTPS going on your local dev instance. Many of the steps are also common for production. The article shows you how to set it up for POW and NGinx, but setting up for Apache and Passenger isn't too dissimilar. The Apache config is different. But Passenger install and setup should be just the same as a http environment. Just need to make sure the secure virtual host in your Apache config points to your application.