devise snippets

Sending Devise Emails Manually

Tagged devise, email  Languages ruby
user = User.new email: 'bill@gates.com'
Devise.mailer_sender = 'no-reply@gates.com'
Devise.mailer.confirmation_instructions(user, self).deliver!

How to generate HAML views for Devise

Tagged haml, rails3, devise  Languages ruby

This will generate HAML views with Rails 3, HAML >=3.0.18 (won't work with lower version), and the latest devise version:

$ rails generate devise:views -e haml

If you see the following error when running the command:

Required dependency ruby_parser not found!
    Run "gem install ruby_parser" to get it.
Required dependency hpricot not found!
    Run "gem install hpricot" to get it.

make sure you have the following dependencies in Gemfile:

group :development do
  gem 'hpricot'
  gem 'ruby_parser'
end

Validating HTML Emails with Nokogiri, Tidy, and validator.w3.org

Tagged tidy, validate, nokogiri, emails, devise  Languages ruby
# We're validating the HTML generated by the Devise mailer
user = User.new email: 'xxx@xxx'
mail = Devise.mailer.confirmation_instructions(user, self).deliver
html = mail.html_part.body.to_s

Validate with tidy:

File.open('/tmp/html-validation.html', 'w') { |f| f << html }
unless system "tidy -errors -q -f /tmp/validation-errors.txt /tmp/html-validation.html"
  fail "Validation failed:\n #{File.read('/tmp/validation-errors.txt')}"
end

Remember to install tidy first:

$ sudo apt-get install tidy

Validate with Nokogiri is not so fun or accurate:

# Validate XML
doc = Nokogiri.XML(html)
doc.errors

# Validate against a schema, if you want
xsd = Nokogiri::XML::Schema(open('http://www.w3.org/2002/08/xhtml/xhtml1-strict.xsd'))
xsd.validate(doc)

For validation with w3.org, see this script

How to implement multiple OmniAuth strategies for Devise

Tagged authentication, facebook, omniauth, devise  Languages ruby

This snippet is useful if you're using Devise and OmniAuth for authentication and need to support authentication with, for example, two separate Facebook applications.

First, put this in, for example, lib/omniauth_i18n.rb:

# The "name" method defines the URL, so the URL becomes /users/auth/facebook_x
module OmniAuth::Strategies
   class FacebookX < Facebook
    def name 
       :facebook_x
    end 
  end
  class FacebookY < Facebook
    def name 
       :facebook_y
    end 
  end
end

Configure each strategy separately in config/initializers/devise.rb:

config.omniauth :facebook_x, 'yyy', 'yyy'
config.omniauth :facebook_y, 'zzz', 'zzz'

This was tested with devise 1.1, oa-auth 0.1.6 and oauth 0.4.4, and will probably break sometime in the future. OmniAuth supports dynamic strategies

How to post a message to the Facebook wall with OmniAuth/Devise

Tagged facebook, devise, omniauth  Languages ruby

In your OmniAuth/Devise-callback controller add this line:

# https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema
session['fb_access_token'] = omniauth['credentials']['token']

This will save the auth_token, which we’ll need for accessing the Facebook API.

Next, in your Devise initializer, usually config/initializer/devise.rb, request additional permissions:

config.omniauth :facebook, 'heh', 'lol', :scope => 'publish_stream,email,offline_access,manage_pages'

The offline_access permission means you can use the token even if the user logs out.

Now if a user logs in you’ll have access to the user’s Facebook access_token, which can be used to post to his wall.

api_key = 'heh'
api_secret = 'lol'

client = OAuth2::Client.new(api_key, api_secret, :site => 'https://graph.facebook.com')
token = OAuth2::AccessToken.new(client, session['fb_access_token'])
token.post('/me/feed', :message => "testing")

To understand how it all works, read about Facebook permissions, the Graph API and the documentation on the post command.

Getting the Access Token

You can also use this URL to get a permanent access_token:

https://graph.facebook.com/oauth/access_token?type=client_cred&client_id=<app_key>&client_secret=<app_secret>

Posting links

Use http://developers.facebook.com/docs/reference/api/link/ to post links.

Posting to a page

When posting to a page you need to change "me" to the page name:

token.post('/acmexxx/post', :message => "testing")

If you need to post to the page as the page itself, not the admin user, you need to get the access_token for the page.

First you need to add the manage_pages permission:

config.omniauth :facebook, 'heh', 'lol', :scope => 'publish_stream,email,offline_access,manage_pages'

You should now login as the page admin and get a new access_token, which you can then use to get a list of accounts and pages you are the administrator for:

https://graph.facebook.com/me/accounts?access_token=<admin_access_token>

You should see the access_token for each page listed in the response, use it to post to the page as the page.

How to Test Authentication With Devise+Capybara+Minitest

Tagged devise, capybara, authentication, warden, transaction, gotcha, minitest  Languages ruby

Testing authentication functionality with Capybara and Devise? See the following checklist:

* Use shared connections or disable transactional fixtures. * Set Capybara.default_host to match config.session_store.domain or you'll get "401 Unauthorized" * Name of test should end with "integration", e.g. describe "Dashboard Business integration" do * Add the following to your integration tests:

include Warden::Test::Helpers
  Warden.test_mode!

  after do
    Warden.test_reset!
  end

Full example of integration test with Devise, Capybara, and minitest:

class IntegrationSpec < MiniTest::Spec
  include Rails.application.routes.url_helpers
  include Capybara::DSL
  include Warden::Test::Helpers
  Warden.test_mode!

  before do
    @routes = Rails.application.routes
  end

  after do
    Warden.test_reset!
  end

  def sign_in(user)
    login_as(user, scope: :user)
  end

  def sign_out
    logout(:user)
  end

  def default_url_options
    Rails.configuration.action_mailer.default_url_options
  end
end

MiniTest::Spec.register_spec_type( /integration$/, IntegrationSpec )

Integration Tests With Capybara, Devise, Minitest::Spec, and Capybara-Webkit

Tagged capybara, devise, minitest, spec, webkit, headless  Languages ruby

Does your boss want you to run integration tests with Capybara, Devise, Minitest::Spec, Capybara-Webkit, and the Headless gem?

Then use this code, which features: * Automatic test failure on JavaScript errors * Check for XSS attack vectors with assert_no_alerts. * Sign in/out with Devise

require 'headless'
require 'awesome_print'

headless = Headless.new(reuse: true, destroy_at_exit: false)
puts "Headless mode. Display :#{headless.display}. PID #{Process.pid}"
headless.start

class IntegrationSpec < MiniTest::Spec
  include Rails.application.routes.url_helpers
  include Capybara::DSL
  include Warden::Test::Helpers
  Warden.test_mode!

  before do
    assert_no_js_errors
  end

  after do
    Warden.test_reset!
  end

  def sign_in(user, scope = :user)
    login_as(user, scope: scope)
  end

  def sign_out(scope = :user)
    logout(scope)
  end

  def assert_no_js_errors
    errors = page.driver.error_messages
    assert_equal 0, errors.size, errors.ai
  end

  def assert_no_alerts(types = [:alert, :confirm, :prompt])
    types.each do |type|
      alerts = page.driver.send(:"#{type}_messages")
      assert_equal 0, alerts.size, alerts.ai
    end
  end

  def default_url_options
    Rails.configuration.action_mailer.default_url_options
  end
end

MiniTest::Spec.register_spec_type( /integration$/, IntegrationSpec )

Remember to name your tests like this:

require 'test_helper'

describe "Dashboard integration" do
...
end

Otherwise the tests won't inherit from the IntegrationSpec class.

Updating Passwords and Emails When Using Active Admin and Devise

Tagged active_admin, password, email, devise  Languages ruby

With Active Admin and Devise, we want to: * Skip email confirmations * Require password and email confirmations, but only when changing the email or password

This code supports our requirements:

ActiveAdmin.register User do
  controller do
    def update
      if params[:user][:password].blank?
        params[:user].delete("password")
        params[:user].delete("password_confirmation")
      end
      if params[:user][:email].blank?
        params[:user].delete("email")
        params[:user].delete("email_confirmation")
      end
      super
    end
  end

  before_save do |user|
    user.skip_confirmation!
    user.skip_reconfirmation!
  end
end

See the Active Admin DSL for details