broom’s blog

Tag: rails

Memos on “Advanced YAML Fixtures” of RoR

by broom9 on Oct.08, 2008, under myPoorTech

YAML Fixtures in Rails 2.0 have some pretty cool features. One of them is “auto generated primary IDs”, and another cooler one is “Label references for associations (belongs_to, has_one, has_many)”. You can find explanations and examples of them in the link above. But there is a pitfall to notice: the second feature actually depends on the first one. In other words, “Label references for associations” may not work if you’re not applying auto generated IDs in your fixture.

The method behind the scene of auto generated IDs feature is Fixture#identify, which is simply a hash process on the label of the fixture row. When the fixture loader handles the label references, it will call the Fixture#identify method directly to get the ID of associated models. So here is a typical failure case.

### in pirates.yml
reginald:
   id: 1
   name: Reginald the Pirate
   monkey: george
### in monkeys.yml
george:
   name: George the Monkey
   pirate: reginald # the fixture loader will use the result of Fixture.identify('reginald') here! not "1".

Using hashed label as auto generated ID is a pretty smart idea. It avoids the troubles to find fixture references between each other and the pain of detecting fixture reference loop. There is a plugin named “Fixture Reference” which actually solves the problem in this tedious way. But I prefer the Rails 2.0 way because it looks more elegant and smarter.

However, sometimes we still need to include primary IDs in the fixtures, for some constants like country/state/city/timezone. Sometimes it’s easier to export them from the database as CSV, since fixture loader can handle CSV files. In this case, refer them in other fixtures by ID, not by label. Or to be safer, don’t give these fixtures label at all.

So the best practice and maybe the “correct” way to use Rails 2.0 fixture is : Specify either ID or label , don’t mix them in a single fixture file.

Comments Off :, more...

A Pitfall of skip_before_filter

by broom9 on Aug.30, 2008, under myPoorTech

In rails, a common task is to use skip_before_filter to skip a certain global before_filter on several actions.
For example

  skip_before_filter :authenticate, :only => [:login]

But if somehow we did calls in this format twice

  skip_before_filter :authenticate, :only => [:login]
  skip_before_filter :authenticate, :only => [:index]

Then only the latest one will work, the action “login” will be filtered by “authenticate” again, in the example above.
This is a little bit reasonable, because you might mean the latest set when you specify “only” repeatedly. But it WAS a pitfall I fell into. Maybe an option like “:overwrite” on the “before_filter” will be more friendly to user.

Comments Off :, , more...

Before_filter Order in Rails

by broom9 on May.28, 2008, under myPoorTech

A typical way to add before filter to controllers in Rails is use the codes like this in controllers

class ApplicationController < ActionController::Base
  before_filter :login_required
  ...
end

And if we declare more than one before filter, they are put into an array and form a filter chain. “filter_chain” is a class inheritable attribute of controller class, so you could use this line in Rails console to check what filters are working for a certain controller.

c: \> ruby script\console
>> puts Services::AdvertiserController.filter_chain.
>>   map(&:filter).join("\n")
login_required
......
authorize
=> nil
>>

But sometimes plugins and other codes will try to add before_filter in a tricky way.

  ActionController::Base.send :before_filter, :authorize

When the 2 declaration ways of before_filter mix together, it’s easy to be confused the order of before filters… For example, the “login_required” filter should work before “authorize” (check permissions of a user). But if I enable authorize before_filter in a “init.rb” file of a plugin, it will probably work before “login_required”.

And if you add a before_filter twice, it will appear in the filter chain twice. If you want to make sure a filter runs after another, a dirty trick is

skip_before_filter :login_required, :authorize
before_filter :login_required, :authorize

But this will make ppl confused even faster.

By the way, the plugin load order in Rails 1.2.x is not reliable either. Here is an intro about it, and Rails 2.0 has improved this feature.

So, my conclusion about before_filter, a best practice, is to avoid enabling before_filter in plugins or lib files, just provide the before_filter and let the app developers decide when and in what order to enable it.

1 Comment :, , more...

The magical “self” when doing Mixin in Ruby

by broom9 on Apr.15, 2008, under myPoorTech

Here is a sample code snippet, which will show my problem. I put this file in the script directory of a Rails project to run.

$:.unshift(File.dirname(__FILE__) + "/../vendor/rails/activesupport/lib")
require 'active_support'

class App
end

module M
  def self.included(base)
    base.class_eval do
      class_inheritable_accessor :h
    end
    base.extend ClassMethods
  end
  module ClassMethods
    def not_work
      h = 1
    end
    def work
      self.h = 2
    end
  end
end
App.send(:include, M)

puts App.h
App.not_work
puts App.h
App.work
puts App.h

You could see that the “self” keyword made a difference when calling the reader method of a class_inheritable_reader. This looks really weird until I checked the implementation of class_inheritable_reader.

 def class_inheritable_reader(*syms)
    syms.each do |sym|
      next if sym.is_a?(Hash)
      class_eval <<-EOS
        def self.#{sym}
          read_inheritable_attribute(:#{sym})
        end

        def #{sym}
          self.class.#{sym}
        end
      EOS
    end
  end
2 Comments :, more...

How to View Rails Log "Colorfully" in Windows

by broom9 on Nov.11, 2007, under myPoorTech

I was learning Ruby on Rails recently and it’s pretty impressive that Rails has done almost every annoying settings and configurations for you….ok, this post isn’t about saying good words for RoR. I want to show my tiny survey on “how to view the Rails log file in Windows”.

As default, Rails produces a very nice log file under the directory “%project_home%/log”, recording detail information of every request, such as path, parameters, session data, SQLs… They are nicely indented and colored by some ascii color controlling characters (I don’t know the exact name of these characters… anyone who knows that please tell me, thank you), but the console in Windows doesn’t support that. So the log will appear like below in windows console.

rails_log_windows

The “tail” command here is from GNUWin32 CoreUtils.

Apparently this is far from nice…

After tried some tools, including UltraEdit, RadRails (console window), Tail for Win32. I surprisingly found a small tool AsciiArtViewer (author’s homepage, download link) can display these color controlling stuff correctly… But this tool can’t work like the tail command (updating realtimely), so I continued my search.

Finally I got a good tool – MinGW-msys. Actually it’s a Minimal SYStem, based on MinGW and offering a Bourne Shell environment. It has the built-in “tail” command and displays color controlling characters correctly. The download page is here, and what you should look for is “MSYS Base System“. I’m using MSYS-1.0.10.exe.

rails_log_msys

The color theme of msys console can be configured by editing the file “c:\msys\1.0\msys.bat”.

————

Some co-worker told me in RadRails it’s also possible to get a pretty format. Right click the log file in resource navigator and choose “Tail” :)

————

Another update, Install Cygwin and add the “bin” directory of cygwin to system path, then everything will be fine….It’s a shame not to realize this earlier =_=

3 Comments :, , , more...