While upgrading Rails from V4.0 to V4.1.1, i encountered the error “Cannot define multiple ‘included’ blocks for a Concern” while deploying the code changes to production server:

 * 2014-09-13 10:00:35 executing `deploy:build_missing_paperclip_styles'
  * executing multiple commands in parallel
........
*** [err :: investingnote.com] rake aborted!
*** [err :: investingnote.com] ActiveSupport::Concern::MultipleIncludedBlocks: Cannot define multiple 'included' blocks for a Concern
*** [err :: investingnote.com] /home/investingnote/shared/bundle/ruby/2.0.0/gems/activesupport-4.1.5/lib/active_support/concern.rb:126:in `included'

I have a concern called notifiable.rb under app/models, the structure of the concern is very standard as in the Rails API for Concern. The following is the brief code for the concern and the model class (in a different file) that include the concern.

module Notifiable
   extend ActiveSupport::Concern
   included do
     require 'eventmachine'

     after_create :create_notification
     ...
   end
end

class Post
  include Notificable
end

I can’t see any problem with this code. I have found some people complaining this problem ActiveSupport::Concern and Rails.config.cache_classes. It is not really quite related to the problem i am facing. So i suspected it should be something wrong with the paperclip compatibility with Rails 4.1.1. Here is the git issue Error on rake paperclip:refresh:missing_styles

The solution is to update your Paperclip to V4.2.0 by running bundle update. Paperclip latest version is compatible with Rails 4.1.

bundle update paperclip

We have set up the rails application with nginx as a reverse proxy. However, the following line of code is giving some trouble:

%a{:href => root_url(email: invitation.email_address, token: invitation.token)}

The root_url is supposed to render the absolute url with domain names. However, it rendered in production as “http://backend/?email=a%40a.com&token=1″ instead of “http://investingnote.com/?email=a%40a.com&token=1″. In another word, the Rails root_url is using the wrong host name with reverse proxy set up.

The problem is caused by the following Nginx set up.

upstream backend {
  server prod2:8000;
  server prod1:8000;
}
server {
        # other config here...
        location @puma {
          proxy_pass http://backend;
        }
}

When the backend puma server received the request, it thinks that the host name is ‘backend’ instead of the actual host. The solution is to preserve the Host header when using proxy pass.

server {
        # other config here...
        location @puma {
          proxy_pass http://backend;
          proxy_set_header Host $host;
        }
}

I was trying to integrate Amcharts into my Rails application today. And I met the error “Cannot read property ‘construct’ of undefined” in the amstock.js file. My charts.js manifest file looks like below:

//= require_tree ../../../vendor/assets/javascripts/amcharts
//= require_tree ./charts

The folder amcharts contains the three compulsory javascript files amcharts.js, serial.js, amstock.js. Tried googling for the answer but didn’t find anyone mentioned the same issue. It was just me…

The problem is because the three javascript files have to be loaded in this strict sequence amcharts.js, serial.js, amstock.js. When I require the whole folder amcharts, the serial.js is loaded last, however amstock.js requires serial.js to be loaded first. The working manifest file looks like

//= require ../../../vendor/assets/javascripts/amcharts/amcharts.js
//= require ../../../vendor/assets/javascripts/amcharts/serial.js
//= require_tree ../../../vendor/assets/javascripts/amcharts
//= require_tree ./charts

This article explains how you can use Zoho to send emails in your Rails application. Zoho provides a lite package that offers 5 user accounts each with 5 GB storage. So it is a good start for a small website.

I tried to set up mail sending with Zoho using action mailer with below settings.

  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address:                'smtp.zoho.com',
    port:                      465,
    user_name:              'support@investingnote.com',
    domain:                 'example.com',
    password:               'password',
    authentication:         :plain
  }
  config.action_mailer.default_url_options = { host: 'localhost:3000' }

When I try to send emails, it took around half a minute and throw the exception Net::ReadTimeout.

This may be caused by the Zoho server ignores the connection because it requires secure connections like SSL/TLS. FastMail’s article provides a very good explanation in the mail server/client communications and SSL/TLS and Starttls. Below are some exacts. 

  • SSL and TLS both provide a way to encrypt a communication channel between two computers (e.g. your computer and our server). TLS is the successor to SSL and the terms SSL and TLS are used interchangeably unless you’re referring to a specific version of the protocol.
  • STARTTLS is a way to take an existing insecure connection, and upgrade it to a secure connection using SSL/TLS. Note that despite having TLS in the name, STARTTLS doesn’t mean you have to use TLS, you can use SSL.

Standard SMTP uses 25, on the configuration we are using port 465. From here, we can tell that we might need to provides the SSL or TLS as an option. Below is modified configuration.

  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address:                'smtp.zoho.com',
    port:                      465,
    user_name:              'support@investingnote.com',
    domain:                 'example.com',
    password:               'password',
    authentication:         :plain,
    ssl:                    true,
    tls:                    true,
    enable_starttls_auto:   true
  }
  config.action_mailer.default_url_options = { host: 'localhost:3000' }

However, it still throws EOFError sometimes when sending email. I am using devise for authentication. Under config/initializers/devise.rb, there is one line specified the sender.

config.mailer_sender = 'no-reply@example.com'

When I specify the sender as no-reply@example.com which I don’t really create on the Zoho mail server, the mail server doesn’t send back correct message and action mailer EOFError is thown.

EOFError (end of file reached): 
/Users/Shanison/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/openssl/buffering.rb:174:in `sysread_nonblock' 
/Users/Shanison/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/openssl/buffering.rb:174:in `read_nonblock' 
/Users/Shanison/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/protocol.rb:153:in `rbuf_fill' 
/Users/Shanison/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/protocol.rb:134:in `readuntil' 
/Users/Shanison/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/protocol.rb:144:in `readline' 
/Users/Shanison/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/smtp.rb:931:in `recv_response' 
/Users/Shanison/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/smtp.rb:917:in `block in getok' 
/Users/Shanison/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/smtp.rb:941:in `critical' 
/Users/Shanison/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/smtp.rb:915:in `getok' 
/Users/Shanison/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/smtp.rb:909:in `quit' 
/Users/Shanison/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/smtp.rb:615:in `do_finish' 
/Users/Shanison/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/smtp.rb:522:in `ensure in
start' 
/Users/Shanison/.rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/net/smtp.rb:522:in `start'  mail (2.5.4) lib/mail/network/delivery_methods/smtp.rb:112:in `deliver!'

To fix the problem, you have to use an email account that does actually exists. I created an account support@example.com instead of no-reply@example.com. Although we tell users don’t reply, it is better we create a real email account, which we can used to track the email sent.


Two more things, Starttls is designed to use one port as normal IMAP/POP/SMTP. So it can upgrades if the server requires it. We can remove the “starttls: true” configuration as we know the port is from standard port, but it makes no difference. Remember to change the default_url_options in your production.rb.

  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address:                'smtp.zoho.com',
    port:                      465,
    user_name:              'support@investingnote.com',
    domain:                 'example.com',
    password:               'password',
    authentication:         :plain,
    ssl:                    true,
    tls:                    true
  }
  config.action_mailer.default_url_options = { host:  'localhost:3000' }

Ruby on Rails has changed a lot these few years. There are some security issues found recently. One of them is regarding the vulnerability in the JSON parser that comes with Active Support. You can read more here. However, the patch provided is only available for Rails 2.3.x and 3.0.x. I checked the code for Rails 2.2.2 and found that this version is affected as well. Without the official patch, I have to come up with my own patch for that. This is a serious problem if your application is not up to date with Rails. I developed a Ruby on Rails website that provides stocks information about three years ago with a small team, which stayed with Rails 2.2.2. Now it is time to upgrade it to the latest Rails 3.2.12. Below is how I did it and some of the major changes that has to be made in the code.

 

The whole project structure has changed quite a lot between Rails 2 and Rails 3 especially with the introduction of asset pipeline and bundlers. The easier way to upgrade your apps is to create a blank new Rails 3 apps and move in all the new folders into your old Rails 2 apps. For the files with the same names under same directories e.g. config/environments.rb, config/environments/production.rb, there are some API/format changes, so you need to compare the contents and see how to merge them. After you have done that, you can try to start your rails applications, which I believe the server can’t even be started. You should check every single error messages shows up in the console and fix them one by one until everything is fine. Below are some major changes that I met with.

 

  1. For the app/controllers/application.rb, it should be named as application_controller.rb now. Otherwise ‘uninitialized constant ApplicationController’ would be thrown.
  2. ENV['RAILS_ENV'] is now deprecated, use Rails.env instead.
  3. Rails.root class used to be String. Now it is changed to PathName. So you can’t do things like below:
    File.read(Rails.root + "/config/streaming_config.yml")
  4. lib folders are not auto loaded. So you will see some missing constant errors. To auto load the lib folders add below two lines to the config/application.rb.
    config.autoload_paths += %W(#{config.root}/lib)
    config.autoload_paths += Dir["#{config.root}/lib/**/"]
  5. filter_parameter_logging is no longer available. To filter out the parameters you can do it in the config/application.rb.
    config.filter_parameters += [:password]
  6. You cannot access controller methods in the view with @controller anymore. You have to use controller instead.
  7. For action view rendering, you no longer need to call h(string) to escape HTML output, it is on by default in all view templates. In Rails 2 you need to do below to escape the parameters, if not, you are vulnerable for XSS attacks.
    <%= h @params[:user_name] %>

    In Rails 3, this html escape is on by default. However if the variable or contents you are trying to render contains html, and you want to render the html you have to explicitly call raw methods or html_safe method.

    <%= raw @page.content %>
    <%= @page.content.html_safe %>

    I forget to put raw or html_safe in some of the views, and it renders escaped html instead. So you may want to check across the whole site to make sure everything is alright.

  8. For form_tag and form_for, you need to use <%= %> instead of <% %>, otherwise the form won’t be rendered at all.
  9. will_paginate 2 won’t work with Rails 3. Have to upgrade to will_paginate 3 otherwise uninitialized constant ActiveRecord::Associations::AssociationCollection error will be thrown.
  10. Array.paginate will throw error.The Array#paginate method still exists, too, but is not loaded by default. If you need to paginate static arrays, first require it in your code: require ‘will_paginate/array’
  11. For active record, save(false) changed to
    save(:validate => false)
  12. request.request_uri changed to request.url
  13. REXML::Document is not auto loaded, need to explicitly require it before using.
    require 'rexml/document'
  14. rake API changes. The :needs => :environments is deprecated. In Rails 2 :
    task :task_name, :argument_name, :needs => :environment do |t,args|
        # ...
     end

    In Rails 3, you have to do the following:

    task :task_name, [:argument_name] => :environment do |t,args|
        # ...
     end
  15. params[:path] used to be an array of the path split by slash. e.g. you might see the value as ['user', 'details.html'], now it is a string /user/details. Note that params[:path] doesn’t contains the format.
  16. interpreate_status is not in use any more. You can use Rack::Utils::HTTP_STATUS_CODES[status_code] to do the same thing.
  17. Mailer API changes. In Rails 2, you would call deliver_welcome_email or create_welcome_email. This has been deprecated in Rails 3.0 in favour of just calling the method name itself. So you can call Mailer.welcome_email.
  18. Mail API changes. In Rails 2 you define a mailer like below (this example is copied from rails guide)
    class UserMailer < ActionMailer::Base
      def welcome_email(user)
        recipients    user.email
        from          "notifications@example.com"
        subject       "Welcome to My Awesome Site"
        sent_on       Time.now
        body          {:user => user, :url => "http://example.com/login"}
      end
    end

    However in Rails 3 above codes has to be changed to below:

    class UserMailer < ActionMailer::Base
      def welcome_email(user)
        @user = user
        @url =  "http://example.com/login"
        mail(
            :to            => user.email
            :from       =>    "notifications@example.com"
            :subject    =>   "Welcome to My Awesome Site"
            :date        =>       Time.now
        )
      end
    end
  19. If a action name is not defined in the controller but the corresponding views file exists, in Rails 2, it will call method_missing. However in Rails 3, it won’t call method_missings. Thus in the help controller we can’t use the method_missing to dynamic rendering the views.