Running with Ruby

Tag: Rails (page 2 of 59)

Trailblazer + Devise: Integrating Devise validatable model with Trailblazer operation + error propagation

Devise is one of those gems that are tightly bound to the Rails stack. It means that as long as you follow the “Rails way” and you do things the recommended way, you should not have any problems.

However, Trailblazer is not the recommended way and the way it works, not always makes it painless to integrate with external gems (note: it’s not a Trailblazer fault, more often poorly designed external gems). Unfortunately Devise is one of those libraries. Models have validations, things happen magically in the controllers and so on.

Most of the time, you can leave it that way, as the scope of what Devise does is pretty isolated (authentication + authorization). But what if you want to integrate it with Trailblazer, for example to provide a custom built password change page? You can do this by following those steps

  • Provide a contract with similar (or the same) validation rules as Devise (this will make it easier to migrate if you decide to drop model validations)
  • Create an operation that will save the contract and propagate changes to the model
  • Copy model errors (if any) into contract errors

Here’s the code you need (I removed more complex validation rules to simplify things):

# Contract object
class Contracts::Update < Reform::Form
  include Reform::Form::ActiveRecord
  # Devise validatable model
  model User

  property :password
  property :password_confirmation

  validates :password,
    presence: true,
    confirmation: true
  validates :password_confirmation,
    presence: true
end

Operation is fairly simple as well:

class Operations::Update < Trailblazer::Operation
  include Trailblazer::Operation::Model
  contract Contracts::Update
  # Devise validatable model
  model User

  def process(params)
    validate(params[:user]) do
      # When our validations passes, we can try to save contract
      contract.save do |hash|
        # update our user instance
        model.update(hash)
        # and propagate any model based errors to our contract and operation
        model.errors.each { |name, desc| errors.add(name, desc) }
      end
    end
  end

And the best part – controller:

class PasswordsController < BaseController
  def edit
    respond_with(form Operations::Update)
  end

  def update
    respond_with(run Operations::Update)
  end

Errbit + HTTPS: Setting up Errbit reporter (Airbrake v5 gem) to work with self-signed HTTPS certificate

Note: If you’re using old Errbit version (0.2.0, 0.4.0) and an old Airbrake version (v4) please refer to this manual to make it work with self-signed certificates.

Having an error catcher like Errbit behind SSL is generally a good idea. Especially when Errbit is hosted on a different server than you application (for example when you manage multiple apps with one Errbit instance). In many cases you will have a self-signed certificate (why would you pay for a cert for internal tool). If you try to use it with Airbrake, you will see following error:

Airbrake:
  HTTP error: SSL_connect returned=1 errno=0 state=unknown state: certificate verify failed

Unfortunately, global SSL certificates verification disabling hack (solution that used to work with Airbrake notifier v4) won’t work:

# No longer working!
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

Luckily, Airbrake notifier is written pretty well, so hacking it (and disabling per request SSL certificate verification) is not hard at all. Here’s a full code you need to place in config/initializers/errbit.rb to make it work:

module Patches
  module Airbrake
    module SyncSender
      def build_https(uri)
        super.tap do |req|
          req.verify_mode = OpenSSL::SSL::VERIFY_NONE
        end
      end
    end
  end
end

Airbrake::SyncSender.prepend(::Patches::Airbrake::SyncSender)

After that (and configuring Airbrake notifier), you can test it out like this:

Airbrake.notify :test
Olderposts Newerposts

Copyright © 2017 Running with Ruby

Theme by Anders NorenUp ↑