Best ruby-on-rails questions in September 2010

BDD with Cucumber and rspec - when is this redundant?

20 votes

A Rails/tool specific version of: How deep are your unit tests?

Right now, I currently write:

  • Cucumber features (integration tests) - these test against the HTML/JS that is returned by our app, but sometimes also tests other things, like calls to third-party services.
  • RSpec controller tests (functional tests), originally only if the controllers have any meaningful logic, but now more and more.
  • RSpec model tests (unit tests)

Sometimes this is entirely necessary; it is necessary to test behavior in the model that is not entirely obvious or visible to the end-user. When models are complex, they should definitely be tested. But other times, it seems to me the tests are redundant. For instance, do you test method foo if it is only called by bar, and bar is tested? What if bar is a simple helper method on a model that is used by and easily testable in a Cucumber feature? Do you test the method in rspec as well as Cucumber? I find myself struggling with this, as writing more tests take time and maintaining multiple "versions" of what is effectively the same behaviors, which makes maintaining the test suite more time intensive, which in turn makes changes more expensive.

In short, do you believe there is there a time when writing only Cucumber features is enough? Or should you always test at every level? If you think there is a grey area, what is your threshold for "this needs a functional/unit test." In practical terms, what do you do currently, and why (or why not) do you think it's sufficient?


EDIT: Here's an example of what might be "test overkill." Admittedly, I was able to write this pretty quickly, but it was completely hypothetical.

Good question, one I've grappled with recently while working on a Rails app, also using Cucumber/RSpec. I try to test as much as possible at every level, however, I've also found that as the codebase grows, I sometimes feel I'm repeating myself needlessly.

Using "Outside-in" testing, my process usually goes something like: Cucumber Scenario -> Controller Spec -> Model Spec. More and more I find myself skipping over the controller specs as the cucumber scenarios cover much of their functionality. I usually go back and add the controller specs, but it can feel like a bit of a chore.

One step I take regularly is to run rcov on my cucumber features with rake cucumber:rcov and look for notable gaps in coverage. These are areas of the code I make sure to focus on so they have decent coverage, be it unit or integration tests.

I believe models/libs should be unit tested extensively, right off the bat, as it is the core business logic. It needs to work in isolation, outside of the normal web request/response process. For example, if I'm interacting with my app through the Rails console, I'm working directly with the business logic and I want the reassurance that methods I call on my models/classes are well tested.

At the end of the day, every app is different and I think it's down to the developer(s) to determine how much test coverage should be devoted to different parts of the codebase and find the right balance so that your test suite doesn't bog you down as your app grows.

Here's an interesting article I dug up from my bookmarks that is worth reading: http://webmozarts.com/2010/03/15/why-not-to-want-100-code-coverage/

How do I vendorize gems for Rails3/Bundler

13 votes

In Rails 2.X, I could simply copy gems into vendor/gems/gem_name, or use the rake command rake gems:unpack. Since Rails3 uses bundler, it doesn't appear to work anymore. I have found the command bundle package, but it doesn't work the same way.

Edit:

So, just to elaborate a bit on this:

The way that rails 2 worked, I could easily grep to find stuff in vendor/gems. If they are bundled up in .gem files, that isn't possible. Also, when developing a gem/plugin, it's very helpful to have it placed within a rails application to test it out in context. How would I do such things with bundler/rails3? Is my workflow inherently broken somehow?

Answering the second part of your question, developing a plugin/gem and shipping it with the rails app without making the gem publicly available, you may do this

Gemfile

gem 'my_private_gem', :path => "vendor/gems/my_private_gem-VERSION"

assuming you performed a gem unpack my_private_gem-VERSION --target vendor/gems

note: bundle package unpacks all gems (as many as in Gemfile.lock). I wouldn't want those in git.

Make bundler use different gems for different platforms

12 votes

I'm working on upgrading one of our Rails 2.3.8 apps to Rails 3, and have run into an annoying problem with bundler and deployment. I develop the application on a Windows machine, but the production environment is running Ubuntu Linux. Now, my problem is that bundler is ignoring the mysql gem in the production environment, and Passenger spits out: "!!! Missing the mysql gem. Add it to your Gemfile: gem 'mysql', '2.8.1'"

Here is my Gemfile:

# Edit this Gemfile to bundle your application's dependencies.
# This preamble is the current preamble for Rails 3 apps; edit as needed.
source 'http://rubygems.org'

gem 'rails', '3.0.0'
gem 'net-ldap', :require => 'net/ldap'
gem 'highline', :require => 'highline/import'
gem 'mysql', '2.8.1'
gem 'net-ssh', :require => 'net/ssh'

# Bundle gems for the local environment. Make sure to
# put test-only gems in this group so their generators
# and rake tasks are available in development mode:
group :development, :test do
  gem 'fakeweb', :require => 'fakeweb'
  gem 'flexmock', :require => 'flexmock/test_unit'
end

As you can see, the mysql gem is specified. However, when deploying, bundler ignores it. Why? The reason is that Bundler generates the following Gemfile.lock (only relevant parts included):

....
mime-types (1.16)
mysql (2.8.1-x86-mingw32)
net-ldap (0.1.1)
....

Notice that it includes the platform specific gem. This is obviously NOT what I want it to do, as that gem is not suitable (and appearently ignored) when running under Linux.

So, does Bundler come with any way to deal with these issues? Or do I have to remember to manually change the mysql gem version in the generated Gemfile.lock every time I run bundle install on my development machine?

Thank you in advance!

Update

It seems like the bundler team is aware of this issue.

This is a known issue in Bundler. The workarounds are either:

  • Generate a Gemfile.lock on a system similar enough to your production environment that you get results that match your production platform. Effectively, that means you can only generate the Gemfile.lock file on Windows if your production system is Windows.
  • Don't commit a Gemfile.lock file at all, and determine dependencies on the production machine at deploy time (bundle install without --deploy). While not recommended in general, this is an often-used workaround until the bug is fixed. For example, this is the recommended solution offered by Heroku.
  • Switch to JRuby, which would have the same platform string across both Windows and Linux (java). I don't recommend this seriously, but I believe it would fix the problem.
  • Fix the problem in the Bundler source code, i.e., help the Bundler team fix the bug. :)

is ruby on rails (or at least the community) dying?

12 votes

This is an honest question and I am not trolling.

As a newbie to rails I've been search for good rails resources. But I've been noticing many sites that apparently were once popular now being completely abandoned. Some examples:

Am I just coincidentally going to all the wrong websites/blogs (even though they're the top hits on google) or is the rails community slowly dying off? If I just happen to be going to the wrong sites can someone please point me to some currently updated sites?

Ruby on Rails was a Hype. That means a lot of people jumped on the bandwagon because that is what they do: jumping on bandwagons (for a living).

After that hype, many communities popped up, in various languages that mimique Rails. Or try to. Or just took the good ideas and applied them to their community. Now you have gazillion halfbaked PHP-frameworks, and a few actually good ones. You have Django (python), Zend, Symphony (PHP) and even in Ruby, some alternative frameworks. That has spread the attention. There used to be only One Good Framework (sic.) now there are many.

That said, Rails 3 has just been released. Rails 3 is cutting-edge again. It has all the ingredients for noSQL (the one-but-latest Hype) HTML5 (the latest Hype) and many javascript-frameworks and interactions (the next-to-be Hype).

That said, Rails is not just Hypes. It is actually a fantastic framework. With a still very active community around it. Just look at github, and visit the trending repo's there once in a while and you will see a Great Rails Thing there every week.

If you want to keep up to date, I would advice:

Rails 3 SSL Deprecation

11 votes

I am upgrading an application to Rails 3.0.0 and am wondering if the standard method for adding SSL has changed (I vaguely remember demos indicating the router could now handle SSL, though I'm not sure if it was just for demonstration purposes). I currently use the "ssl_requirement" gem, however it gives:

DEPRECATION WARNING: Using #request_uri is deprecated. Use fullpath instead. (called from ensure_proper_protocol at /Library/Ruby/Gems/1.8/gems/ssl_requirement-0.1.0/lib/ssl_requirement.rb:53)

Also, it appears to break when handling the new 'data-method' attributes. For example:

<%= link_to "Logout", user_path, :method => :delete %>

Works fine when accessing from an SSL section of the application, but fails (attempts to render show action) when followed from a non-SSL section (all actions in the user controller require SSL, although I understand that the destroy action does not transmit secure data).

It's indeed pretty simple in Rails 3. In config/routes.rb:

MyApplication::Application.routes.draw do
  resources :sessions, :constraints => { :protocol => "https" }
end

Or if you need to force SSL for multiple routes:

MyApplication::Application.routes.draw do
  scope :constraints => { :protocol => "https" } do 
    # All your SSL routes.
  end
end

And linking to SSL routes can be done like this:

<%= link_to "Logout", sessions_url(:protocol => 'https'), :method => :delete %>

If you wish to automatically redirect some controllers (or actually, some subpaths) to an equivalent https-based URL, you can add something like this to your routes (I wish this part were simpler):

# Redirect /foos and anything starting with /foos/ to https.
match "foos(/*path)", :to => redirect { |_, request|
  "https://" + request.host_with_port + request.fullpath }

Rails Restful Routing and Subdomains.

9 votes

I wondered if there were any plugins or methods which allow me to convert resource routes which allow me to place the controller name as a subdomain.

Examples:

map.resources :users
map.resource :account
map.resources :blog
...

example.com/users/mark
example.com/account
example.com/blog/subject
example.com/blog/subject/edit
...

#becomes

users.example.com/mark
account.example.com
blog.example.com/subject
blog.example.com/subject/edit
...

I realise I can do this with named routes but wondered if there were some way to keep my currently succinct routes.rb file.

The best way to do it is to write a simple rack middleware library that rewrites the request headers so that your rails app gets the url you expect but from the user's point of view the url doesn't change. This way you don't have to make any changes to your rails app (or the routes file)

For example the rack lib would rewrite: users.example.com => example.com/users

This gem should do exactly that for you: http://github.com/jtrupiano/rack-rewrite

UPDATED WITH CODE EXAMPLE

Note: this is quickly written, totally untested, but should set you on the right path. Also, I haven't checked out the rack-rewrite gem, which might make this even simpler

# your rack middleware lib.  stick this in you lib dir
class RewriteSubdomainToPath

  def initialize(app)
    @app = app
  end

  def call(env)
    original_host = env['SERVER_NAME']
    subdomain = get_subdomain(original_host)
    if subdomain
      new_host = get_domain(original_host)
      env['PATH_INFO'] = [subdomain, env['PATH_INFO']].join('/')
      env['HTTP_X_FORWARDED_HOST'] = [original_host, new_host].join(', ')
      logger.info("Reroute: mapped #{original_host} => #{new_host}") if defined?(Rails.logger)
    end

    @app.call(env)

  end

  def get_subdomain
    # code to find a subdomain.  simple regex is probably find, but you might need to handle 
    # different TLD lengths for example .co.uk
    # google this, there are lots of examples

  end

  def get_domain
    # get the domain without the subdomain. same comments as above
  end
end

# then in an initializer
Rails.application.config.middleware.use RewriteSubdomainToPath

Is it possible to access rails guides for rails 2.3?

9 votes

It used to be that the ruby on rails guides for version 3.0 were at http://edgeguides.rubyonrails.org/ and the guides for version 2.3 were at http://guides.rubyonrails.org . Now that version 3 has been released, its guides have been moved to the main URL.

Is there any way to access the guides for rails 2.3?

I think the old guides are still here: http://guides.rubyonrails.org/v2.3.8/index.html - they're for v2.3.8. Hope that helps!

How can I make cookies secure (https-only) by default in rails?

9 votes

In a Rails controller, I can set a cookie like this:

cookies[:foo] = "bar"

And specify that the "secure" (https-only) flag be on like this:

cookies[:foo, :secure => true] = "bar"

:secure is false by default. How can I have cookies be secure by default, application-wide?

This is on Rails 2.3.8

Thanks knx, you sent me down the right path. Here's the monkeypatch I came up with, which seems to be working:

class ActionController::Response
  def set_cookie_with_security(key, value)
    value = { :value => value } if Hash != value.class
    value[:secure] = true
    set_cookie_without_security(key, value)
  end
  alias_method_chain :set_cookie, :security
end

What do you think?

What components make VIM a good (great) ruby editor?

9 votes

I'm learning ruby on rails on a linux box and dusting off my VIM skills (skillz?).

alt text

When I got started on VIM way back in my c++ days, I had a friend with a great vimfiles folder that had tons of stuff to get started. Starting from scratch, vim is great, but it feels like it could be a lot better.

I currently have:

I know that barely scratches the surface of what some more experienced vim/ruby devs have (including the one offs in the vim.rc file).

Is there a list somewhere (or could we create one) of a bunch of the standard vim configurations needed to make programming ruby (and rails) more fun? Is there a zip/tarball somewhere with a good base setup?

take a look at tim pope's repos on git hub. Many, many awesome vim plugins and extensions for working with ruby and rails

http://github.com/tpope

Need Advice: Is this a good use case for a 'NoSQL' Database? If so, which one?

9 votes

I have recently been researching NoSql options. My scenario is as follows:

We collect and store data from custom hardware at remote locations around the world. We record data from every site every 15 minutes. We would eventually like to move to every 1 minute. Each record has between 20 and 200 measurements. Once set up the hardware records and reports the same measurements every time.

The biggest issue we are facing is that we get a different set of measurements from every project. We measure about 50-100 different measurement types, however any project can have any number of each type of measurement. There is no preset set of columns that can accommodate the data. Because of this we create and build each projects data table with the exact columns it needs as we set up and configure the project on the system.

We provide tools to help analyze the data. This typically includes more calculations and data aggregation, some of which we also store.

We are currently using a mysql database with a table for each client. There are no relations between tables.

NoSql seems promising because we could store a project_id, timestamp then the rest would not be preset. This means one table, more relationships in the data, yet still handling the variety of measurements.

Is a 'NoSql' solution right for this job? If so which ones?

I have been investigation MongoDB and it seems promising...

Example for Clarification:

Project 1 has 5 data points recorded, the mysql table columns look like: timestamp, temp, wind speed, precipitation, irradiance, wind direction

Project 2 has 3 data points recorded mysql table columns: timestamp, temp, irradiance, temp2

The simple answer is that there is no simple answer to these sort of problems, the only way to find out what works for your scenario is to invest R&D time into it.

The question is hard to answer because the performance requirements aren't spelled out by the OP. It appears to be 75M/year records over a number of customers with a write rate of num_customers*1minute (which is low), but I don't have figures for the required read / query performance.

Effectively you have already a sharded database using horizontal partitioning because you're storing each customer in a seperate table. This is good and will increase performance. However you haven't yet established that you have a performance problem, so this needs to be measured and the problem size assessed before you can fix it.

A NoSQL database is indeed a good way of fixing performance problems with traditional RDBMS, but it will not provide automatic scalabity and is not a general solution. You need to find your performance problem fix and then design the (nosqL) data model to provide the solution.

Depending on what you're trying to achieve I'd look at MongoDB, Apache Cassandra, Apache HBase or Hibari.

Remember that NoSQL is a vague term typically encompassing

  • Applications that are either performance intensive in read or write. Often sacrificing read or write performance at the expense of the other.
  • Distribution and scalability
  • Different methods of persistency (RAM/Disk)
  • A more structured/defined access pattern making ad-hoc queries harder.

So, in the first instance I'd see if a traditional RDBMS can achieve the required performance, using all available techniques, get a copy of High Performance MySQL and read MySQL Performance Blog.

Rev1:

In light of your comments I think it is fair to say that you could achieve what you want with one of the above NOSQL engines.

My primary recommendation would be to get your data model designed and implemented, what you're using at the moment isn't really right.

So look at Entity-attribute-value model as I think it is exactly right for what you need.

You need to get your data model right before you can consider which technology to use, being honest modifying schemas dynamically isn't a datamodel.

I'd use a traditional SQL database to validate and test the new datamodel as the management tools are better and it's generally easier to work with the schemas as you refine the datamodel.

Install Rails 3 on OSX with RVM

8 votes

Trying to install the new Rails 3 release on OSX 10.6.

Have never touched Ruby or Rails on this machine since purchased.

I was able to get rvm and get Ruby 1.9.2. installed. From there, I am stuck.

I tried:

rvmsudo gem install rails -v 3.0.0
sudo gem install rails --pre
sudo gem install rails
sudo gem update rails

And I get the same result error each time:

ERROR:  While executing gem ... (Errno::ENOENT)
    No such file or directory - /Users/kevin/.rvm/gems/ruby-1.9.2-head@rails3/cache/activesupport-3.0.0.gem

If I do gem list, it says LOCAL GEMS and doesn't list anything.

I have read a few walkthroughs but honestly none of them address this issue and its kind of pissing me off. Why is this so difficult to install? Would love to learn it if someone could help me get it running.

I was trying to follow this:

http://eddorre.com/posts/installing-rails-3-beta-4-using-rvm

and this:

http://hivelogic.com/articles/compiling-ruby-rubygems-and-rails-on-snow-leopard

Which is actually linked from the ROR guides website. Am I missing dependencies? How do I get them in?

If I do rails -v I get:

rails -v
/Library/Ruby/Site/1.8/rubygems.rb:779:in `report_activate_error': Could not find RubyGem rails (>= 0) (Gem::LoadError)
    from /Library/Ruby/Site/1.8/rubygems.rb:214:in `activate'
    from /Library/Ruby/Site/1.8/rubygems.rb:1082:in `gem'
    from /usr/bin/rails:18

Older versions of rvm had a bug that can cause your ruby versions to get crosswired because the OS can cache executable paths for the which command (particularly if you are using zsh). See this long, detailed, mind blowing post by Yehuda Katz on the subject.

What I had to do this morning:

rvm update && rvm reload # update rvm
rvm gemset delete rails3 # delete old gemset
rvm install 1.9.2
rvm use 1.9.2
rvm gemset create rails3
rvm use 1.9.2@rails3
which ruby          # check to be sure the ruby interpretter is properly set to 1.9.2
hash -r             # if ruby interpretter is not pointing to 1.9.2
gem install rails
which rails         # check to be sure we are using rvm version of rails

Boson vs Thor for console applications

8 votes

Has anyone used both:

Boson: http://tagaholic.me/2009/10/14/boson-command-your-ruby-universe.html

and

Thor: http://github.com/wycats/thor

Thor are very popular and have more followers and contributers than Boson, but Boson looks far more powerful than Thor and the architecture is very well thought out.

In Boson you:

  • can add methods that are used both in the console and ruby environment. So you don't have to both have Thorfiles for console and gems for ruby.
  • can have aliases.
  • don't have to install your script files, you just put them in ~/.boson/commands. I always have to struggle with uninstalling and installing Thorfiles after each update (which could be every minute when editing the source code, very frustrating).
  • have much nicer commands output than thor.
  • don't have to write the argument descriptions by hand like in Thor.
  • work with modules, which are better than with classes cause you can include modules inside other modules.
  • wrap open source snippets (eg. from Gist) inside a module automatically and it works with Boson immediately.
  • have different views for your method results.
  • don't have to recode anything in your snippets to fit Thor, since it only use native ruby code (modules). That means if you one day don't want to use Boson, you don't have to recode everything, which you have to if you are using Thor.
  • The API http://rdoc.info/github/cldwalker/boson is more well documented - like tutorials inside each class.
  • You can just include the "boson" modules inside your ruby script and use them directly, something I cannot with Thor, cause it is only for Thor. You can't share the Thor methods with other Thor classes (not as mixins)

I noticed all these benefits just from reading the documentation and played with Boson for a couple of minutes.

Should I use Thor just because it's more popular (cause I can't find anything else where it shines over boson) or should I take the risk that Boson may be unmaintained after a while, since the author is the only contributor?

Although it's just one guy you see how he has managed to code in a rapid speed and with outstanding quality. Would be great if more contributers like him contributed to that library. I really hope more rubyists are going to use it cause it has a lot of potential for being THE scripting framework for all system automation. Like a Rails for the backend. And the author really helps you out very fast when you file an issue.

Thor only works for the shell (which I guess is its purpose) while boson as I see it has 3 main functionalities. It allows you to have code working in the shell, in ruby (irb and scripts) and you can have nice collections of all your Ruby codes, without modifications.

I have always wanted a framework to be my backend scripting framework, and now I don't have to reinvent the wheel. It seems that boson could be it.

Has someone used both these libraries and could share some thoughts?

Disclaimer: I'm the author of boson.

I've used both and thor was what inspired me to write boson. While the two have overlapping functionality, I see them as having different goals.

Thor is a scripting framework which quickly and beautifully gives applications a commandline interface. The 116 gems (including rails) that depend on it are good evidence of that. Initially I tried using thor to manage and use snippets but after awhile, the forced namespacing, the lack of aliasing, writing redundant usage lines, and poor searching, made me realize thor wasn't optimized to manage snippets.

So I wrote boson to manage the endless number of ruby snippets I used to put in ~/bin with this philosophy in mind. At 400+ commands, I'm able to instantly find and use any ruby snippet as a full-blown executable. There are too many features to go over here, though you seem to know some of boson's strengths. As for being the sole contributor, I welcome anyone to contribute their ideas.

If there was one simple comparison to make between the two, I'd say thor is centered around creating executables for projects and apps while boson is centered around creating them for users.

DEPRECATION WARNING in Rails3 for before_create, before_update, before_save, before_destroy

8 votes

I just upgraded my application from Rails 2.3 to 3 and I'm getting some DEPRECATION WARNINGS for my before_create ,update, save, destroy etc.

Does anyone know how ot fix the issue?

These are my Warnings :

DEPRECATION WARNING: Base#before_create has been deprecated, please use Base.before_create :method instead. (called from /Users/macmini/qna/app/models/user.rb:32)
DEPRECATION WARNING: Base#before_update has been deprecated, please use Base.before_update :method instead. (called from /Users/macmini/qna/app/models/user.rb:40)
DEPRECATION WARNING: Base#after_save has been deprecated, please use Base.after_save :method instead. (called from /Users/macmini/qna/app/models/user.rb:50)
DEPRECATION WARNING: Base#before_destroy has been deprecated, please use Base.before_destroy :method instead. (called from /Users/macmini/qna/app/models/user.rb:56)

Just one example for the before_create :

  def before_create
    self.username.downcase!
    self.salt = User.make_salt(self.username)
    self.hashed_password = User.hash_with_salt(@password, self.salt)
  end

The warning you're seeing is Rails 3's attempt to discourage you from overwriting the base before_* and after_* methods. This is similar to how you would have before_filter and other callbacks in your controller.

What this means is that instead of doing:

def before_create
  self.username.downcase!
  self.salt = User.make_salt(self.username)
  self.hashed_password = User.hash_with_salt(@password, self.salt)
end

Rails wants you to do:

before_create :downcase_username_and_create_password

def downcase_username_and_create_password
  self.username.downcase!
  self.salt = User.make_salt(self.username)
  self.hashed_password = User.hash_with_salt(@password, self.salt)
end

In this case, you might even split up the two, as there could be a possibility that you'd want to generate a password independently:

before_create :downcase_username, :create_password

def downcase_username
  self.username.downcase!
end

def create_password
  self.salt = User.make_salt(self.username)
  self.hashed_password = User.hash_with_salt(@password, self.salt)
end

cache_money for Rails 3

8 votes

I've used various forks (mostly the ngmoco fork) of Nick Kallen's excellent cache_money for several Rails 2.3 based project, but we're now making the leap to Rails 3 which, thanks to the introduction of ActiveRelation, does not work with the popular forks of cache_money.

Is there a fork of cache_money, or an equivalent write-through cache, that is compatible with Rails 3 ?

There are a branch rails 3 in ngmoco fork to use you :

http://github.com/ngmoco/cache-money/tree/rails3

You can try it I don't know if it's really works.

You can add this in your Gemfile by

gem 'cache_money', :git => 'git://github.com/ngmoco/cache-money.git', :branch => 'rails3'

What is the best way of running shell commands from a web based interface?

7 votes

Imagine a web application that allows a logged in user to run a shell command on the web server at the press of a button. This is relatively simple in most languages via some standard library os tools.

But if that command is long running you don't want your UI to hang. Again this is relatively easy to deal with using some sort of background process or putting the command to be executed onto a message queue (and maybe saving the output and status somewhere for later consumption). Just return quickly saving we'll run that and get back to you.

What I'd like to do is show the output of said web ui triggered shell command as it happens. So vertically scrolling text like when running in a terminal.

I have a vague idea of how I might approach this, streaming the output to a websocket perhaps and simply printing the output to screen.

What I'd like to ask is:

Are their any plugins, libraries or applications that already do this. Something I can either use or read the source of. Ideally an open source python/django or ruby/rails tool, but other stacks would be interesting too.

So, I've tried to answer my own question with code as I couldn't find anything to quite fit the bill. Hopefully it's useful to anyone coming across the same problem.

Redbeard 0X0A pointed me in the general direction, I was able to get a stand along ruby script doing what I wanted using popen. Extending this to using EventMachine (as it provided a convenient way of writing a websocket server) and using it's inbuilt popen method solved my problem.

More details here http://morethanseven.net/2010/09/09/Script-running-web-interface-with-websockets.html and the code at http://github.com/garethr/bolt/

When to add what indexes in a table in Rails

7 votes

I have a question about Rails database.

  • Should I add "index" to all the foreign keys like "xxx_id"?
  • Should I add "index" to the automatically created "id" column?
  • Should I add "index(unique)" to the automatically created "id" column?

  • If I add index to two foreign keys at once (add_index (:users, [:category, :state_id]), what happens? How is this different from adding the index for each key?

    class CreateUsers < ActiveRecord::Migration
      def self.up
        create_table :users do |t|
          t.string :name
          t.integer :category_id 
          t.integer :state_id
          t.string :email
          t.boolean :activated
          t.timestamps
        end
      # Do I need this? Is it meaningless to add the index to the primary key?
      # If so, do I need :unique => true ?
      add_index :users, :id 
      # I don't think I need ":unique => true here", right?
      add_index :users, :category_id # Should I need this?
      add_index :users, :state_id # Should I need this?
      # Are the above the same as the following?
      add_index (:users, [:category, :state_id])
      end
    end
    

Great answer so far. Additional question.

  • I should add "index with unique" for xxx_id, right?

Should I add "index" to all the foreign keys like "xxx_id"?

It would be better, because it accelerates the search in sorting in this column. And Foreign keys are something searched for a lot.

Should I add "index" to the automatically created "id" column?

No, this is already done by rails

Should I add "index(unique)" to the automatically created "id" column?

No, same as above

If I add index to two foreign keys at once (add_index (:users, [:category_id, :state_id]), what happens? How is this different from adding the index for each key?

Then the index is a combined index of the two columns. That doesn't make any sense, unless you want all entries for one category_id AND one state_id (It should be category_id not category) at the same time.

An Index like this would speed the following request up:

# rails 2
User.find(:all, :conditions => { :state_id => some_id, :category_id => some_other_id })

# rails 3
User.where(:state_id => some_id, :category_id => some_other_id)

Where

add_index :users, :category_id
add_index :users, :state_id

will speed up these requests:

# rails 2+3
User.find_by_category_id(some_id)
User.find_by_state_id(some_other_id)

# or
# rails 2
User.find(:all, :conditions => {:category_id => some_id})
User.find(:all, :conditions => {:state_id => some_other_id})

# rails 3
User.where(:category_id => some_id)
User.where(:state_id => some_other_id)

I should add "index with unique" for xxx_id, right?

No, because if you do this, only one user can be in one category, but the meaning of category is that you can put more many user into one category. In your User model you have something like this belongs_to :category and in your Category model something like has_many :users. If you have a has_many relationship the foreign_key field must not be unique!

For more detailed information on this you should take a look at tadman's great answer.

When to use node.js vs sinatra vs rails?

7 votes

What are the best uses for these 3 languages/frameworks? Is it useful to mix all of them (or 2)?

If you're building a complete web application, you should probably use Rails as it provides the most comprehensive services. You can also leverage an enormous amount of work produced by the community.

Sinatra is great for producing really thin, no-nonsense application services. You don't get much to work with, but it is very fast. If you need a database connection, you will have to add it in, and things like this can make creating even medium-sized applications a challenge. Basically if you need something very simple and don't need Rails, you probably need Sinatra.

node.js is a great new framework for producing responsive, scalable applications, but it doesn't have nearly the library of add-ons that a mature platform like Rails does. node.js really excels at applications based on streaming and on-demand data transformation. Some of the examples produced in Node Knockout are very interesting, but these were produced by some exceptional teams.

While the Node Knockout entries are very well done, when compared to the sort of applications that were produced in the 2009 Rails Rumble they seem to come across as toys lacking depth and complexity. This is not to discredit the work done by the Node Knockout teams, but it does show that the strengths of node.js are mostly to do with real-time events and less with conventional more ordinary DB-based apps.

Rails 3 -- Bundler/Capistrano Errors

7 votes

I have a basic Rails 3 app working locally on my development box, but want to test out deploying early on to make sure everything works. I'm using Capistrano to deploy.

When I run cap deploy (after all the other necessary setup), it breaks on this command with this error:

[...]
* executing 'bundle:install'
* executing "bundle install --gemfile /var/www/trex/releases/20100917172521/Gemfile --path /var/www/trex/shared/bundle --deployment --quiet --without development test"

servers: ["www.[my domain].com"]
[www.[my domain].com] executing command
** [out :: www.[my domain].com] sh: bundle: command not found
command finished
[...]

So it looks like it can't find the bundle command on the server.

However, when I log in to the server...

$ ruby -v
ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux]
$ rails -v
Rails 3.0.0
$ bundle -v
Bundler version 1.0.0

...the bundle command works just fine.

What could be going wrong?

-

(Furthermore, for completeness:)

$ which ruby
~/.rvm/rubies/ruby-1.9.2-p0/bin/ruby
$ which rails
~/.rvm/gems/ruby-1.9.2-p0/bin/rails
$ which bundle
~/.rvm/gems/ruby-1.9.2-p0/bin/bundle

Okay, though I still haven't gotten a full cap deploy to work, I did fix this problem. The problem was Capistrano trying to use a different path for Bundler (and other gems) than the RVM paths.

Check your Capistrano path by doing cap shell, then echo $PATH. You'll probably see your standard /usr/local/bin and /usr/bin, but that's not where RVM has Bundler, et al., stored.

Edit your Capistrano config/deploy.rb file, and add the following lines, per these instructions:

# Add RVM's lib directory to the load path.
$:.unshift(File.expand_path('./lib', ENV['rvm_path']))

# Load RVM's capistrano plugin.    
require "rvm/capistrano"

set :rvm_ruby_string, '1.9.2'
set :rvm_type, :user  # Don't use system-wide RVM

That finally got Capistrano to see Bundler and start loading gems appropriately.

Delete link sends "Get" instead of "Delete" in Rails 3 view.

7 votes

I'm using Rails 3 and have have a page that outputs a list of posts from the database. I'd like to be able to delete a post from a link.

The 2nd example below works, but the first doesn't. Anybody know why the first won't work? My view contains:

# this link sends a "GET" request which asks for the #show function  
<%= link_to 'Delete', post, :method => :delete %>

# this link sends the proper "DELETE" request which asks for the #destroy function
<%= button_to 'Delete', post, :method => :delete %>

My routes file contains the following:

resources :posts 

Make sure that your <head> section in the layout includes the following:

<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>

In Rails 3, the delete requests are being handled with the help of JavaScript to ensure that the request is being sent correctly. If you don't have the csrf meta tags and the required JavaScript code, delete links won't work. The :defaults JavaScript files include--among others--prototype.js, and application.js. The latter contains the stuff that makes the link work, but relies on the Prototype framework.

If you don't want to use the default Prototype JavaScript libraries, there are ports of application.js for several other frameworks. You can find the jQuery one here, for instance.

Buttons will still work regardless of JavaScript, as the HTML code generated with button_to includes all necessary information by itself. This is why you're seeing the button work while the link doesn't.

Rails 3: How to create a new nested resource?

7 votes

The Getting Started Rails Guide kind of glosses over this part since it doesn't implement the "new" action of the Comments controller. In my application, I have a book model that has many chapters:

class Book < ActiveRecord::Base
  has_many :chapters
end

class Chapter < ActiveRecord::Base
  belongs_to :book
end

In my routes file:

resources :books do
  resources :chapters
end

Now I want to implement the "new" action of the Chapters controller:

class ChaptersController < ApplicationController
  respond_to :html, :xml, :json

  # /books/1/chapters/new
  def new
    @chapter = # this is where I'm stuck
    respond_with(@chapter)
  end

What is the right way to do this? Also, What should the view script (form) look like?

First you have to find the respective book in your chapters controller to build a chapter for him. You can do your actions like this:

class ChaptersController < ApplicationController
  respond_to :html, :xml, :json

  # /books/1/chapters/new
  def new
    @book = Book.find(params[:book_id])
    @chapter = @book.chapters.build
    respond_with(@chapter)
  end

  def create
    @book = Book.find(params[:book_id])
    @chapter = @book.chapters.build(params[:chapter])
    if @chapter.save
    ...
    end
  end
end

In your form, new.html.erb

form_for(@chapter, :url=>book_chapters_path(@book)) do
   .....rest is the same...

or you can try a shorthand

form_for([@book,@chapter]) do
    ...same...

Hope this helps.