RailsCasts Pro episodes are now free!

Learn more or hide this

Balazs Nagy's Profile

GitHub User: julian7

Site: http://blog.js.hu/

Comments by Balazs Nagy

Avatar

My latest revision of reading yaml'ed data in application.rb (1.9 notation):

ruby
read_yaml = ->(fname) do
  begin
    YAML.load(File.read(File.expand_path("../#{fname}", __FILE__)))
  rescue Errno::ENOENT
    {}
  end
end

appconfig = read_yaml.('application.yml')
defaults = read_yaml.('application_defaults.yml')
CONFIG = defaults.deep_merge(appconfig)
CONFIG.merge! CONFIG.fetch(Rails.env, {})
CONFIG.symbolize_keys!

One less mutation, and it allows specifying environment-dependent settings in both yaml files. It does use mutation though, but as far as I know they (merge! and symbolize_keys!) are both thread-safe.

Avatar

It has been extracted to transitions gem, even before rails 3 came out.

Avatar

Asset precompile can hinder zero downtime too, however it's relatively easy to fix too, if you use nginx:

nginx
  location ~ ^/assets/  {
    gzip_static on;
    try $uri /old$uri;
    expires max;
    add_header  Cache-Control public;
  }

and if you've done generating your public/assets, throw away public/oldassets, and move public/assets to its place!

Avatar

According to a pull request, it looks like 4.0 will accept arrays in permit() params as hash values too, therefore in the example, you can write this:

ruby
class PermittedParams
  ...
  def topic_attributes
    [:name].tap do |attributes|
      attributes << :sticky if user && user.admin?
      attributes << {posts_attributes: [:post, :attributes]}
    end
  end
  ...
end
Avatar

It doesn't override the files themselves, but those will be used as defaults. All of your locale data will go into copycopter database. You can remove your original files then, and/or you even replace them with a version extracted from the current copycopter database. This means by time you can even shut down your copycopter server.

Avatar

Because you won't be able to use minitest's advanced features if you stick with test/unit.

Avatar

Yep, ruby1.9 implements test/unit using minitest.

Avatar

That's awesome. You figure out a lot of things I'm just lazy to dig out. I'm sure this ep will encourage people to use MiniTest in their projects.

Avatar

That's true, cd doesn't handle autocompletion in cdpaths.

Anyways, I use omz for looking up interesting solutions. I like to keep my shell environment small.

Avatar

To use the proper settings. Maybe rake command starts the wrong version of ruby. Maybe it sets up a wrong configuration... it is written nicely already: http://yehudakatz.com/2011/05/30/gem-versioning-and-bundler-doing-it-right/

Sure, you don't have to use bundle exec. In this case, however, you have to use binstubs, and you have to run commands from there.

Avatar

I'm thinking on a viable solution for this since David's starting keynote. This =depend_on is a good idea, but having two separate lists (one for @import and another for depend_on) is not.

However, we can do it in a different way.

We can put any variable declarations, mixins, functions to a separate file we can depend on, then we can @import them in every single .scss file, and then we can use =require_tree . in application.css.

Rules of thumb:

  • As Ryan mentioned, .scss files get rendered separately, therefore separating declarations from actual @includes doesn't work in sprockets natively.
  • We can @import declarations to every single .scss file.
  • However, while =require'd files can come either from app/assets, lib/assets, and vendor/assets, @import doesn't know the trick. It doesn't even know about Sprocket's require magic (using wildcards, requiring trees, maintaining depends).
  • =require_tree load sequence is defined by the operating system, therefore we can't rely on it.
  • However, =require and =require_tree doesn't load files which are already imported. Therefore use specific =requires for files where ordering is important, and let =require_tree . to do the dirty work.

It looks like we'll have at least a plugin to handle this situation, which might be migrated to sprockets eventually, but for the time being we don't have anything similar.

Avatar

@Tiaglo Scolari: this is the best solution I could find! Simple but effective. I have renamed ajax_loaded to state_pushed, but this is the only modification I could come up with :) (I support AJAX queries even if history state is not available)

Avatar

Well, if you store all three data (eg. hash, salt, and cost), you can update users' password on the fly to increase cost of older encrypted passwords... at successful login:

class User
  DEFAULT_COST = 15

  def self.authenticate(email, password)
    user = where(:email => email).first
    if user
      pw = BCrypt::Password.new(user.password_hash)
      if pw == password
        if pw.cost < DEFAULT_COST
          user.password = password
          user.save
        end
        user
      else
        nil
      end
    else
      nil
    end
  end
  ...
end