isotope|eleven


If you're getting something like undefined local variable or method 'new_user_session_path' after adding mount Refinery::Core::Engine, :at => '/' to config/routes.rb you can use the following fix:

config/initializers/devise.rb

Devise.setup do |config|
    config.router_name = :main_app
end

Devise will now know to use the main_app routes. End of line.

How to remove the purple from your grub menu, and how to get rid of that purple boot screen on Ubuntu:

Step 1:

sudo vim /lib/plymouth/themes/default.grub

# Change your background to black and white will this
if background_color 0,0,0; then
  clear
fi

Step 2:

sudo vim /etc/default/grub

:%s/quiet splash//g

Note: This changes GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" to GRUB_CMDLINE_LINUX_DEFAULT=""

That is all :-)

About_adam_gamble

Easily find or initialize in rails

by: Adam Gamble

October 18th, 2012 15:33

> Team.where(:name => "Testing").where(:conference_id => 1).first
=> nil
> Team.where(:name => "Testing").where(:conference_id => 1).first_or_initialize
=> #<Team id: nil, name: "Testing", conference_id: 1, created_at: nil, updated_at:     nil, logo_image_uid: nil, short_name: nil>
> _.persisted?
=> false
> Team.where(:name => "Testing").where(:conference_id => 1).first_or_create
=> #<Team id: 128, name: "Testing", conference_id: 1, created_at: "2012-10-18 20:26:36", updated_at: "2012-10-18 20:26:36", logo_image_uid: nil, short_name: nil>
> _.persisted?
=> true

I didn't realize this was this elegant in rails, and just stumbled upon it. Maybe you didn't know either?

Enjoy.

@ryanbigg asked me how I set up deployment, figured I'd post this internal guide we've been using.

Derived from this link

The main difference is that this configuration supports rails 3.2.

To set up a server, do the following as root:

echo '--- Install system packages ---'
apt-get update

Let that finish. Then:

apt-get upgrade -y

Let that finish. Then:

apt-get install build-essential ruby-full libmagickcore-dev imagemagick libxml2-dev libxslt1-dev git-core postgresql postgresql-client postgresql-server-dev-8.4 nginx curl node

Let that finish. Then:

apt-get build-dep ruby1.9.1

Install node so you can do asset precompilation later:

sudo apt-get install python-software-properties && sudo add-apt-repository ppa:chris-lea/node.js && sudo apt-get update && sudo apt-get install nodejs nodejs-dev

Then make a deployer user:

useradd -m -g staff -s /bin/bash deployer
passwd deployer

Then fill in the deployer password.

Add this to /etc/sudoers:

%staff ALL=(ALL) ALL

Install system-wide rvm (as root)

bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)

Install ruby

source /etc/profile.d/rvm.sh
rvm install 1.9.2
rvm use 1.9.2@projectname --create
gem install bundler

As your deployer user, add this to your ~/.rvmrc

rvm_trust_rvmrcs_flag=1

Add the following to /etc/environment to always run commands in production on this server.

RAILS_ENV=production

Setup postgres database:

sudo -u postgres createdb projectname_production
sudo -u postgres psql

Then execute the following SQL (use your own password):

CREATE USER projectname_production WITH PASSWORD 'isotope_bang';
GRANT ALL PRIVILEGES ON DATABASE projectname_production TO projectname_production;

Make sure this user can actually log in (by default, only local-system users can). Modify /etc/postgresql/9.1/main/pg_hba.conf and change out the line requiring local users to use ident to md5.

local   all         all                               md5

Restart postgres

/etc/init.d/postgresql restart

Then set up nginx:

# /etc/nginx/sites-available/default
upstream projectname.com {
  # fail_timeout=0 means we always retry an upstream even if it failed
  # to return a good HTTP response (in case the Unicorn master nukes a
  # single worker for timing out).

  # for UNIX domain socket setups:
  server unix:/tmp/projectname.com.socket fail_timeout=0;
}

server {
    # if you're running multiple servers, instead of "default" you should
    # put your main domain name here
    listen 80 default;

    # you could put a list of other domain names this application answers
    server_name projectname.com;

    root /home/deployer/apps/projectname.com/current/public;
    access_log /var/log/nginx/projectname.com_access.log;
    rewrite_log on;

    location / {
        #all requests are sent to the UNIX socket
        proxy_pass  http://projectname.com;
        proxy_redirect     off;

        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

        client_max_body_size       10m;
        client_body_buffer_size    128k;

        proxy_connect_timeout      90;
        proxy_send_timeout         90;
        proxy_read_timeout         90;

        proxy_buffer_size          4k;
        proxy_buffers              4 32k;
        proxy_busy_buffers_size    64k;
        proxy_temp_file_write_size 64k;
    }

    # if the request is for a static resource, nginx should serve it directly
    # and add a far future expires header to it, making the browser
    # cache the resource and navigate faster over the website
    # this probably needs some work with Rails 3.1's asset pipe_line
    location ~ ^/(images|javascripts|stylesheets|system|assets)/  {
      root /home/deployer/apps/projectname.com/current/public;
      expires max;
      break;
    }
}

And then:

# /etc/nginx/nginx.conf 
user deployer staff;

# Change this depending on your hardware
worker_processes 4;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    multi_accept on;
}

http {
    types_hash_bucket_size 512;
    types_hash_max_size 2048;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay off;
    # server_tokens off;

    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    gzip on;
    gzip_disable "msie6";

    # gzip_vary on;
    gzip_proxied any;
    gzip_min_length 500;
    # gzip_comp_level 6;
    # gzip_buffers 16 8k;
    # gzip_http_version 1.1;
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    ##
    # Virtual Host Configs
    ##

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Now start nginx (won't work till unicorn's up but go ahead)

/etc/init.d/nginx start

Add unicorn to your project's Gemfile:

# Gemfile
gem "unicorn"

group :development do
  gem "capistrano"
end

Add unicorn config to your project:

# config/unicorn.rb
# Set environment to development unless something else is specified
env = ENV["RAILS_ENV"] || "development"

# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
# documentation.
worker_processes 4

# listen on both a Unix domain socket and a TCP port,
# we use a shorter backlog for quicker failover when busy
listen "/tmp/my_site.socket", backlog: 64

# Preload our app for more speed
preload_app true

# nuke workers after 30 seconds instead of 60 seconds (the default)
timeout 30

pid "/tmp/unicorn.my_site.pid"

# Production specific settings
if env == "production"
  # Help ensure your application will always spawn in the symlinked
  # "current" directory that Capistrano sets up.
  working_directory "/home/deployer/apps/my_site/current"

  # feel free to point this anywhere accessible on the filesystem
  user 'deployer', 'staff'
  shared_path = "/home/deployer/apps/my_site/shared"

  stderr_path "#{shared_path}/log/unicorn.stderr.log"
  stdout_path "#{shared_path}/log/unicorn.stdout.log"
end

before_fork do |server, worker|
  # the following is highly recomended for Rails + "preload_app true"
  # as there's no need for the master process to hold a connection
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
  end

  # Before forking, kill the master process that belongs to the .oldbin PID.
  # This enables 0 downtime deploys.
  old_pid = "/tmp/unicorn.my_site.pid.oldbin"
  if File.exists?(old_pid) && server.pid != old_pid
    begin
      Process.kill("QUIT", File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
      # someone else did our job for us
    end
  end
end

after_fork do |server, worker|
  # the following is *required* for Rails + "preload_app true",
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
  end

  # if preload_app is true, then you may also want to check and
  # restart any other shared sockets/descriptors such as Memcached,
  # and Redis.  TokyoCabinet file handles are safe to reuse
  # between any number of forked children (assuming your kernel
  # correctly implements pread()/pwrite() system calls)
end

Capify the project:

capify .

Replace config/deploy.rb with the following:

# config/deploy.rb 
require "bundler/capistrano"

set :application,     "projectname.com"
set :scm,             :git
set :repository,      "git@github.com:isotope11/projectname.com.git"
set :branch,          "origin/master"
set :migrate_target,  :current
set :ssh_options,     { forward_agent: true }
set :rails_env,       "production"
set :deploy_to,       "/home/deployer/apps/projectname.com"
set :normalize_asset_timestamps, false

set :user,            "deployer"
set :group,           "staff"
set :use_sudo,        false

role :web,    "192.168.1.154"
role :app,    "192.168.1.154"
role :db,     "192.168.1.154", primary: true

set(:latest_release)  { fetch(:current_path) }
set(:release_path)    { fetch(:current_path) }
set(:current_release) { fetch(:current_path) }

set(:current_revision)  { capture("cd #{current_path}; git rev-parse --short HEAD").strip }
set(:latest_revision)   { capture("cd #{current_path}; git rev-parse --short HEAD").strip }
set(:previous_revision) { capture("cd #{current_path}; git rev-parse --short HEAD@{1}").strip }

default_environment["RAILS_ENV"] = 'production'

# Use our ruby-1.9.2-p318@my_site gemset
default_environment["PATH"]         = "--"
default_environment["GEM_HOME"]     = "--"
default_environment["GEM_PATH"]     = "--"
default_environment["RUBY_VERSION"] = "ruby-1.9.2-p318"

default_run_options[:shell] = 'bash'

namespace :deploy do
  desc "Deploy your application"
  task :default do
    update
    restart
  end

  desc "Setup your git-based deployment app"
  task :setup, except: { no_release: true } do
    dirs = [deploy_to, shared_path]
    dirs += shared_children.map { |d| File.join(shared_path, d) }
    run "#{try_sudo} mkdir -p #{dirs.join(' ')} && #{try_sudo} chmod g+w #{dirs.join(' ')}"
    run "git clone #{repository} #{current_path}"
  end

  task :cold do
    update
    migrate
  end

  task :update do
    transaction do
      update_code
    end
  end

  desc "Update the deployed code."
  task :update_code, except: { no_release: true } do
    run "cd #{current_path}; git fetch origin; git reset --hard #{branch}"
    finalize_update
  end

  desc "Update the database (overwritten to avoid symlink)"
  task :migrations do
    transaction do
      update_code
    end
    migrate
    restart
  end

  task :finalize_update, except: { no_release: true } do
    run "chmod -R g+w #{latest_release}" if fetch(:group_writable, true)

    # mkdir -p is making sure that the directories are there for some SCM's that don't
    # save empty folders
    run <<-CMD
      rm -rf #{latest_release}/log #{latest_release}/public/system #{latest_release}/tmp/pids &&
      mkdir -p #{latest_release}/public &&
      mkdir -p #{latest_release}/tmp &&
      ln -s #{shared_path}/log #{latest_release}/log &&
      ln -s #{shared_path}/system #{latest_release}/public/system &&
      ln -s #{shared_path}/pids #{latest_release}/tmp/pids &&
      ln -sf #{shared_path}/config/database.yml #{latest_release}/config/database.yml
    CMD

    #precompile the assets
    run "cd #{latest_release}; bundle exec rake assets:precompile"

    if fetch(:normalize_asset_timestamps, true)
      stamp = Time.now.utc.strftime("%Y%m%d%H%M.%S")
      asset_paths = fetch(:public_children, %w(images stylesheets javascripts)).map { |p| "#{latest_release}/public/#{p}" }.join(" ")
      run "find #{asset_paths} -exec touch -t #{stamp} {} ';'; true", env: { "TZ" => "UTC" }
    end
  end

  desc "Zero-downtime restart of Unicorn"
  task :restart, except: { no_release: true } do
    run "kill -s USR2 `cat /tmp/unicorn.my_site.pid`"
  end

  desc "Start unicorn"
  task :start, except: { no_release: true } do
    run "cd #{current_path} ; bundle exec unicorn_rails -c config/unicorn.rb -D"
  end

  desc "Stop unicorn"
  task :stop, except: { no_release: true } do
    run "kill -s QUIT `cat /tmp/unicorn.my_site.pid`"
  end  

  namespace :rollback do
    desc "Moves the repo back to the previous version of HEAD"
    task :repo, except: { no_release: true } do
      set :branch, "HEAD@{1}"
      deploy.default
    end

    desc "Rewrite reflog so HEAD@{1} will continue to point to at the next previous release."
    task :cleanup, except: { no_release: true } do
      run "cd #{current_path}; git reflog delete --rewrite HEAD@{1}; git reflog delete --rewrite HEAD@{1}"
    end

    desc "Rolls back to the previously deployed version."
    task :default do
      rollback.repo
      rollback.cleanup
    end
  end
end

def run_rake(cmd)
  run "cd #{current_path}; #{rake} #{cmd}"
end

Now there is one little thing you'll need to do. I like to run my apps, even on the server, to use their own gemset. This keeps everything clean and isolated. Login to the deployer account and create your gemset. Next run rvm info and fill the PATH, GEM_HOME and GEM_PATH variables accordingly.

Place the database configuration on the server in the shared directory.

# /home/deployer/apps/projectname.com/shared/config/database.yml 
production:
  adapter: postgresql
  encoding: unicode
  database: projectname_production
  pool: 5
  username: projectname_production
  password: password

Modify the server to support password-based SSH logins by editing /etc/ssh/sshd_config and setting:

PasswordAuthentication yes

Then restart ssh:

/etc/init.d/ssh restart

Set up a deploy key for the deployer user on your git repository. As deployer run the following:

ssh-keygen

Then:

cat ~/.ssh/id_rsa.pub

Push that as a deploy key to the project on github.

SSH into github as deployer from the server, to let this box validate that the host is valid to connect to:

ssh git@github.com

Then run a capistrano setup for the project:

cap deploy:setup

You also might have to go onto the server and, as deployer, run:

mkdir ~/apps/projectname.com/shared/pids

Deployments

Whenever you have a new feature developed in a feature branch, this is the process of deploying it:

Merge feature_branch into master
Run your tests to make sure everything is dandy.
Push master
Run `cap deploy`

This post isn't really programming related, but it will save a lot of people some grief, and it is computer related. If you've had any problems with YouTube videos looking like the image below, then there are a couple of things you can do to fix this.

Before Fix

First you can simply sign up for the YouTube HTML5 Video Player, but this doesn't solve the problem for the videos that fall back to the Adobe Flash player when they lack compatibility for the new HTML5 player.

To fix the videos that play in flash, right click on a YouTube video you're currently watching and go to "Settings...". Next you'll want to un-check "Enable hardware acceleration"

Settings

Reload the page, and vuala!

After Fix

So on a project we were working on, we had something that looked / acted an awful lot like a normal ActiveRecord association. However, it was a custom method we wrote that returned an ActiveRecord::Relation. This worked fantastically, for everything except for a moderately deep query involving this 'relation.'

The code for the relation looked like this:

# app/models/person.rb
class Person < ActiveRecord::Base
  has_many :person_school_links

  def person_school_links(status = :status_active)
    PersonSchoolLink.where(person_id: self.id).send(status)
  end
end

This let us do @person.person_school_links.more_chained_methods just fine, without causing any grief. We got a few months into this project without trouble.

Then, we were building a report that went across this 'relation.' The report had a query that looked like:

RewardDelivery.includes(to: [ :person_school_links ]).where(to: { person_school_links: { school_id: 1 } })

This query worked fine if there were no matching RewardDeliveries. However, any time it had actual data to return, Rails would throw

undefined method `target' for #<ActiveRecord::Relation:0x000000079e0fa0>

It took quite a bit of digging into the Rails stack to figure out what was happening, but essentially the methods generated by a has_many, etc. relationship in ActiveRecord::Base are not returning ActiveRecord::Relations, but rather something derived from ActiveRecord::Reflection::MacroReflection. Ultimately, when the ActiveRecord::Relation from the above query was coerced into something Array-like, Rails looks for a #target method on the reflection. Since we were returning an ActiveRecord::Relation, and since those don't actually have a #target method defined, it was blowing up.

To get around this and still get our preferred behaviour, I ended up writing a class I called MacroReflectionRelationFacade. I essentially use SimpleDelegator to wrap the ActiveRecord::Relation and add an acceptable #target method to it. Code follows, thought the story was interesting:

# lib/macro_reflection_relation_facade.rb
class MacroReflectionRelationFacade < SimpleDelegator
  def target
    self
  end
end

# app/models/person.rb
require 'macro_reflection_relation_facade'

class Person < ActiveRecord::Base
  has_many :person_school_links

  # Relationships
  def person_school_links(status = :status_active)
    MacroReflectionRelationFacade.new(PersonSchoolLink.where(person_id: self.id).send(status))
  end
end

I'm unsure if this is a perfect solution, but it works perfectly for all my purposes. Enjoy :)

About_josh_adams

Linkdump of Awesome Stuff #6

by: Josh Adams

September 7th, 2012 15:00

About_josh_adams

Linkdump of Awesome Stuff #5

by: Josh Adams

August 31st, 2012 08:11

This week's linkdump has an obvious bias. After some feedback I received from my post on Commands as Resources, a few people pointed me to @avdi's Objects on Rails google group. This led to my spending quite a bit of time researching various approaches people have taken along the same lines as Isotope11 in pursuit of OO'ing up their rails apps. If that interests you, this linkdump should be great :)

And Heath's contributions get their own section, because they're largely js-focused and because he sends so dang many to me :)

Tons of links today. Have something else we need to be talking about? Comments!

About_josh_adams

Linkdump of Awesome Stuff #4

by: Josh Adams

August 25th, 2012 12:41

It's linkdump time! :)

Anything great we're missing? Throw it in the comments! :)

If you missed it, Uncle Bob gave a keynote at Ruby Midwest regarding Rails application structure and being able to intuit a project's functionality from its structure. It really struck a chord with me, and I wanted to share a pattern I've just used for the first time (but considered for quite a while) that really makes me happy.

Commands with ActiveModel

Model, briefly.

So we have a project that has general ledgers. In our model, a Student has a checking account and a savings account. We also have a class called CreditManager that has methods on it that represent each transfer we support within our system. So there are methods in there called transfer_funds_from_checking_to_savings(student, amount) and transfer_funds_from_savings_to_checking(student, amount). Each of these methods are well-tested in the CreditManager's unit tests with mocks ensuring that the ledger models get sent the appropriate messages to handle the transfers.

The old busted way

We have a form in the interface for transferring funds from checking to savings or vice versa. In many Rails apps, this form might submit to a controller action that loads up the CreditManager, checks validations, executes the transfer, and returns. This puts logic into the controller that really doesn't belong there.

In some 'next tier' Rails apps you might see a model built, persisted to the database (but not really used, ideally, for reporting) that was a StudentTransfer. This model might have an after_create that kicked off the credit manager calls. That's a decent step up, but it's really weird to have a database-backed model for this, and inevitably someone starts reporting on 'the ledger' by reading these models, which is....stupid.

Commands!

So the thing I'm doing now, and I'm extremely happy with the result, is to build out a Command class, backed by ActiveModel, to handle this use case.

Benefits
  • Validation of input can be handled, and tested, painlessly.
  • There is an obvious pattern for building a form to execute the command using typical form_for idioms.
  • We will be reusing a custom validator on all transfer commands in the system, so Rails' customer validator framework is very nice.
  • We could easily move to a message based architecture here without missing a beat.
  • Refactoring the bottom layers doesn't affect the controllers at all.
  • Testing a ton of different user interactions can be done entirely at the unit test level, with nary a database connection or session setup to be seen.
Code

So this is a long way to get in a blog post without code, but I figured I'd try to set the stage nicely. Without further ado, here's the relevant bits:

# config/routes.rb
resources :student_transfer_commands


# app/views/banks/_transfer_credits.html.haml
= form_for StudentTransferCommand.new do |f|
  = f.text_field :amount, placeholder: "Amount"
  = f.select :direction, options_for_select([["Checking to Savings", "checking_to_savings"], ["Savings to Checking", "savings_to_checking"]])
  = submit_tag "Transfer"


# app/controllers/student_transfer_commands_controller.rb
class StudentTransferCommandsController < LoggedInController
  def create
    transfer = StudentTransferCommand.new(params[:student_transfer_command])
    transfer.student_id = current_person.id
    if transfer.valid?
      transfer.execute!
      flash[:success] = "Transfer successful."
    else
      flash[:error] = "Invalid transfer."
    end
    redirect_to bank_path
  end
end


# app/models/student_transfer_command.rb
class StudentTransferCommand
  include ActiveModel::Validations
  include ActiveModel::Naming
  include ActiveModel::Conversion

  attr_accessor :amount, :direction, :student_id

  validates :direction, presence: true
  validates :student_id, presence: true, numericality: true
  validates_inclusion_of :direction, in: ["savings_to_checking", "checking_to_savings"]
  validates :amount, positive_decimal: true

  def initialize params={}
    @amount = BigDecimal(params[:amount]) if params[:amount]
    @direction = params[:direction]
    @student_id = params[:student_id]
  end

  # This is so that activemodel acts like we want in the form
  def persisted?
    false
  end

  # The transfer knows what to call on credit manager based on its direction
  def transfer_method
    case direction
    when "savings_to_checking"
      :transfer_credits_from_savings_to_checking
    when "checking_to_savings"
      :transfer_credits_from_checking_to_savings
    else
      raise "unknown direction"
    end
  end

  def student
    Student.find(student_id)
  end

  def credit_manager
    CreditManager.new
  end

  def execute!
    credit_manager.send(transfer_method, student, amount)
  end
end


# app/validators/positive_decimal_validator.rb
class PositiveDecimalValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value.present?
      record.errors[attribute] << "Must be present"
      return false
    end
    unless value.is_a?(BigDecimal)
      record.errors[attribute] << "Must be a BigDecimal"
      return false
    end
    record.errors[attribute] << "Must be positive and non-zero" unless value > BigDecimal('0')
  end
end


# test/unit/student_transfer_command_test.rb
require 'test_helper'

describe StudentTransferCommand do
  subject { StudentTransferCommand.new }

  it "requires valid amount" do
    subject.wont have_valid(:amount).when(nil)
    subject.wont have_valid(:amount).when(0)
    subject.wont have_valid(:amount).when(BigDecimal('-1'))
    subject.wont have_valid(:amount).when('asdf')
    subject.wont have_valid(:amount).when('123')

    subject.must have_valid(:amount).when(BigDecimal('1'))
  end

  it "requires valid direction" do
    subject.wont have_valid(:direction).when(nil)
    subject.wont have_valid(:direction).when("foo")

    subject.must have_valid(:direction).when("savings_to_checking")
    subject.must have_valid(:direction).when("checking_to_savings")
  end

  it "requires valid student_id" do
    subject.wont have_valid(:student_id).when(nil)
    subject.wont have_valid(:student_id).when("foo")

    subject.must have_valid(:student_id).when(1)
  end

  it "knows the type of credit manager transfer to execute based on its direction" do
    subject.direction = "checking_to_savings"
    subject.transfer_method.must_equal :transfer_credits_from_checking_to_savings

    subject.direction = "savings_to_checking"
    subject.transfer_method.must_equal :transfer_credits_from_savings_to_checking
  end

  it "executes the appropriate transfer when #execute! is called" do
    amount = BigDecimal('5')
    subject.amount = amount
    method = :meth
    student = mock "student"
    credit_manager = mock "credit manager"
    subject.expects(:student).returns(student)
    subject.expects(:credit_manager).returns(credit_manager)
    credit_manager.expects(method).with(student, amount).returns(true)
    subject.expects(:transfer_method).returns(method)

    subject.execute!
  end
end

What never shows up in the above? Anything related to ActiveRecord. This is unbelievably fast to test.

Thoughts?

I'd love to hear some feedback on this method. It feels so unbelievably good I don't know where to start.