Bogdan Kulbida - Personal blog.

Software Engineering Consultant

Rails Send_file Issue in IE8

IE8 does not work correctly with Rails send_file. To make it work you need to manually remove the cache headers from the response object.

The simple and dirty way might be to re-define a method send_file in the controller, and some additional behavior and fall back to a super.

application_controller.rb
1
2
3
4
5
6
7
8
9
10
11
  ...

  protected

  def send_file(file_name, options={})
    if request.env['HTTP_USER_AGENT'] =~ /msie.8.0/i
      response.headers.delete('Pragma')
      response.headers.delete('Cache-Control')
    end
    super(file_name, options)
  end

Thanks for viewing.

MiniTest Expectations List

Another portion of MiniTest expectations (extracted from minitest.rb):

Expectations

minitest.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  :assert_empty, :must_be_empty, :unary
  :assert_equal, :must_equal
  :assert_in_delta, :must_be_close_to
  :assert_in_epsilon, :must_be_within_epsilon
  :assert_includes, :must_include, :reverse
  :assert_instance_of, :must_be_instance_of
  :assert_kind_of, :must_be_kind_of
  :assert_match, :must_match
  :assert_nil, :must_be_nil, :unary
  :assert_operator, :must_be, :reverse
  :assert_output, :must_output
  :assert_raises, :must_raise
  :assert_respond_to, :must_respond_to, :reverse
  :assert_same, :must_be_same_as
  :assert_send, :must_send
  :assert_silent, :must_be_silent
  :assert_throws, :must_throw
  :refute_empty, :wont_be_empty, :unary
  :refute_equal, :wont_equal
  :refute_in_delta, :wont_be_close_to
  :refute_in_epsilon, :wont_be_within_epsilon
  :refute_includes, :wont_include, :reverse
  :refute_instance_of, :wont_be_instance_of
  :refute_kind_of, :wont_be_kind_of
  :refute_match, :wont_match
  :refute_nil, :wont_be_nil, :unary
  :refute_operator, :wont_be, :reverse
  :refute_respond_to, :wont_respond_to, :reverse
  :refute_same, :wont_be_same_as

Aliases

1
2
  alias :wont_be_within_delta :wont_be_close_to
  alias :must_be_within_delta :must_be_close_to

How to Reload the Code in Rails Before Each Request

Sometimes you need a way to reload custom file or a code in development environment before each request.

Here is a snippet of the code that you need to put in your development.rb file to re-load any class or a module in Rails. In this particular example I will show you how to re-initialize a constant. This is not a best practice to re-initialize constant however sometimes it comes in handy to do it during development.

development.rb
1
2
3
4
5
6
7
8
9
10
11
12
RailsApp::Application.configure do

  ...

  ActionDispatch::Callbacks.before do
    Object.send(:remove_const, :CONST_NAME)
    ::CONST_NAME = ClassThatReadsTheFile.read
  end

  ...

end

In short, Rails executes before callback method each time you make a request. However don’t do this in production, since it will decrease your app performance.

You may wonder what callbacks are there besides before. Well ActionDispatch::Callbacks.methods will show you the list ;) Enjoy.

Responsibilities

Today let’s talk about responsibilities. It is extremely important topic, especially for the beginners in programming. Who is responsible for what? Of course we are talking about programming stuff and responsibilities whether you develop programs in OO or in procedural way.

The quick example is let’s say you need to take a square root from a number. Let’s take a look at the code in ruby:

sqrt.rb
1
  Math::sqrt(121) # => 11.0

But we can’t get a root from the negative number. So who should take a responsibility for a valid argument?

As a matter of fact ruby works close to how the developer might think, when you will try to do something like

sqrt.rb
1
  Math::sqrt(-121) # => Math::DomainError: Numerical argument is out of domain - "sqrt"

This will raise an exception. Good enough, right? But what to do when the programming language can’t catch this sort of thing rights under the hood? If you will try to do the same in Java language you will not get an exception, you will get NaN instead (Not a Number) value. So the program silently will continue it’s execution with truly invalid postcondition.

The solution is to check for valid data before passing the value to the sqrt function. All the responsibilities should be on the calling program that calls sqrt function.

My suggestion is to avoid additional value pre-processing operations for method parameters and do it in the method/program that calls this method (sqrt for instance) so the actual program will get expected parameters.

This will remove extra logic complexity and keep you focused on what the actual code should do.

If the method gets wrong parameters – raise an exception immediately before do anything. Better raise for sure than proceed with invalid data. Make sure your method gets what it designed for.

However some languages provide you a way to retry operation with changed data, like Ruby for instance. But this extra piece of complexity that you going to add to the code – are you sure it’s worth it? The answer might be it depends. But I don’t agree, the code should be simple for others to understand and be focused on a business logic and not on the fixing parameters to make the method return expected value(s) and just work and not crash.

That’s all for today. Hope you did find something new for your self ;)

MiniTest Expectations

Here are MiniTest::Spec’s key expectations that I use often.

positive_expectations.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  obj.must_be(operator, expected)       - for example, 10.must_be :< , 11
  obj.must_be_close_to                  - the equivalent of assert_in_delta
  obj.must_be_empty                     - Fails unless obj.empty?
  obj.must_be_instance_of(klass)        - Fails unless obj.class == klass
  obj.must_be_kind_of(klass)            - Fails unless obj is of class klass or klass is one of its superclasses.
  obj.must_be_nil
  obj.must_be_same_as                   - tests for true object equality
  lambda {}.must_be_silent
  obj.must_be_within_delta
  obj.must_be_within_epsilon
  obj.must_equal(other)                 - Does a ==/eql? comparison between two objects.
  obj.must_include(other)
  obj.must_match(regex)                 - A regular expression match, e.g. "hello".must_match /w+/
  lambda {}.must_output(stdout, [stderr..]) - The block should have certain output on stdout or stderr. Set stdout to nil just to check stderr.
  lambda {}.must_raise(exception)
  obj.must_respond_to(message)
  obj.must_throw(sym)

Opposite ones:

negative_expectations.rb
1
2
3
4
5
6
7
8
9
10
  obj.wont_be
  obj.wont_be_empty
  obj.wont_be_instance_of
  obj.wont_be_kind_of
  obj.wont_be_nil
  obj.wont_be_same_as
  obj.wont_equal
  obj.wont_include
  obj.wont_match
  obj.wont_respond_to

As you can see MiniTest adds much power to your tests and it supports spec-like DSL.

How to Refactor Fat Class or a Module in Ruby and Rails

This is a blog post about how to refactor a fat classe (or module) in ruby application. Some solution I come up with when working on some heavy project.

Just to be clear, I’m not going to encourage you to use this approach. You may use it as is or you can try to extend it and make it better. Comments are welcome.

Every good programmer loves well structured code, tryes to be DRY as much as possible and hates heavy methods with bunch of lines of crappy code.

All this heavy code slows us down when we try to maintain or fix or add new functionality to the application. Did you ever try to find a bug in the code like this one?

heavy_class.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
class HeavyClass < ActionController::Base

  # ...

  def verify_request
    is_valid, msg = validate_request(params['t'], params['q'])
    status_code = is_valid ? 200 : 500
    status_code = 306 if !is_valid && msg == 306 #if they are trying to register using a WineAgent email, notify them they must contact us
    render(:update, :status => status_code){|page|
      page << msg if !is_valid
    }
  end

  # ...

private

  def validate_request(type, q)
    is_valid, msg = case params['t']
      when 'email' then
        return [true, nil] if session[:wc2010_user]
        if EmailVeracity::Address.new(params['q']).valid?
          r = if !Person.loginable.exists?(:email => params['q'])
            [true, nil]
          else
            [false, t(:'signup.validate_request.email.already_taken')]
          end
          if User.email_domain_is_blacklisted(params['q'])
            r = [false, t(:'signup.validate_request.email.blacklisted')]
          end
          r
        else
          [false, t(:'signup.validate_request.email.invalid')]
        end
      when 'password' then
        u = User.new(:updating_password => true)
        u.password = u.password_confirmation = params['q']
        valid = u.check_password
        if !u.errors.get(:password).blank?
          [valid, u.errors.get(:password).join(',')]
        else
          [valid, u.errors.get(:password)]
        end
      when 'postal_code' then
        zip_code = User::format_zip_code(params['q'])
        u = Person.first
        u.zip_code = params['q']
        u.valid?
        [u.errors.get(:postal_code).nil?, 'Enter a valid Postal Code']
      when 'user_name' then
        u = Person.first
        u.user_name = params['q']
        u.valid?
        msg = u.errors.get(:user_name)
        msg = msg.kind_of?(Array) ? msg.first : msg
        [u.errors.get(:user_name).nil?, "Screen name #{msg}"]
      when 'promotion_code' then
        [params['q'].blank? || (PromoCode::does_exist?(params['q']) || FirstInLineSubscriber::does_exist?(params['q'])), 'You have entered an invalid Promo Code']
      else
        [false, nil]
    end
    return [is_valid, msg]
  end
end

It is terrible and makes me wanna throw my laptop away and make some delicious cakes…

The main adea is to create classes that will follow Single Responsobility Principle (in ideal) and will handle all this functionality.