Follow Along as I Stumble on the Path to Learning RoR

Posts tagged “rails

Using CloudFront with S3 and Paperclip

I wanted to cache my S3 images for my Rails app, so I changed my app to serve images using AWS CloudFront, a CDN.

Doing this was pretty simple.

(1) Set-up a AWS CloudFront instance and your S3 bucket as your origin

(2) Change your Paperclip settings to use the new CloudFront instance.  I did this in production.rb (make sure neither the url or s3_host_alias values are being written by Paperclip settings in your model):

config.paperclip_defaults = {
storage: :s3,
:url => “:s3_alias_url”,
:s3_host_alias => “your-cloud-front-url.cloudfront.net”,
:path => “:rails_env/:class/:attachment/:id/:style/:filename”,
:bucket => “your-bucket-name”,
s3_credentials: {
bucket: ENV[‘AWS_S3_BUCKET’],
access_key_id: ENV[‘AWS_ACCESS_KEY_ID’],
secret_access_key: ENV[‘AWS_SECRET_ACCESS_KEY’],
}
}

and that’s it!

Now, if you check the URL of your images, it should see that their source is prefaced with your CloudFront URL.


NoMethodError undefined method `[]’ for “image”:Sass::Script::Value::String

When upgrading my Rails app to 4 (from 3), I was getting the error:

NoMethodError undefined method `[]’ for “image”:Sass::Script::Value::String

Eventually I found out that the asset-path / asset-url methods changed to only accept one argument.

For example,

asset-url(‘profile.png’, image)

now should be:

asset-url(‘profile.png’)

In my particular case, this code was in some of my css files.


Useful Rails Testing Gems

Here’s a list of Rails gems that have been helpful in testing for me:

RSpec Rails – for using the RSpec framework for testing

Capybara – for testing the app like a visitor would interact with the web app

Factory Girl Rails – makes it easy to create instances of models and associations

Shoulda Matchers – makes it easier to test and verify things with methods that use easy to understand language

Database Cleaner – to help keep your test environment from having a bunch of extra and redundant data

Warden – since I use Devise, this makes it easy to sign in in my Capybara tests without having to go to the login screen each time (and then to the pages I really want to test)

Guard – allows me to automatically test the code and specs that I change so I don’t need to remember to manually kick off a test each time a change is made

Launchy – useful with Capybara tests when I can’t figure out why a test is failing.  Launchy launches a browser so you can see the contents of the page.’save_and_open_page’ line to your spec when you want to do this.

 


Adding WYSIWYG / Rich Text Editor to Rails App

I wanted to allow my users to format text input into a text area, so I decided to use CKEditor.  Luckily, there’s a great gem for this.  For my Rails app (Rails 4), all I had to do to get started was:

  1. Add this to the gemfile: gem ‘ckeditor’
  2. bundle install
  3. Add this to application.js: //= require ckeditor/init
  4. Adjust my text area in the form, I’m using the Simple Form gem (the documentation shows how to integrate with different form types): <%= f.input :text, label: “Lesson Text”, :as => :ckeditor, input_html: { :ckeditor => {:toolbar => ‘Full’} %>
  5. In config/initializers/assets.rb add this: Rails.application.config.assets.precompile += %w( ckeditor/* )

That’s all you need to do to get started with CKEditor.  However, this default comes with a ton of options for editing text.  For my site, it was too much.  For example, I did not want to allow some formatting changes, such as font size, font type, or color just so I could keep a consistent look across my app.  Also, I didn’t want to allow people to be able to upload files using the editor (although you can – the documentation shows you how to do this by tying the upload to Carrierwave or Paperclip).

So I needed to create a custom toolbar configuration.  Luckily, the gem makes this easy.

In app/assets/javascripts/ckeditor/config.js you need to add configuration.  The easiest way for me to do this was to copy the configuration from the gem (in the gem’s files – app > assets > javascripts > ckeditor) into the file, and then cut out what is not needed:

/*
Copyright (c) 2003-2011, CKSource – Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/

CKEDITOR.editorConfig = function( config )
{
// Define changes to default configuration here. For example:
// config.language = ‘fr’;
// config.uiColor = ‘#AADC6E’;

/* Filebrowser routes */
// The location of an external file browser, that should be launched when “Browse Server” button is pressed.
config.filebrowserBrowseUrl = “/ckeditor/attachment_files”;

// The location of an external file browser, that should be launched when “Browse Server” button is pressed in the Flash dialog.
config.filebrowserFlashBrowseUrl = “/ckeditor/attachment_files”;

// The location of a script that handles file uploads in the Flash dialog.
config.filebrowserFlashUploadUrl = “/ckeditor/attachment_files”;

// The location of an external file browser, that should be launched when “Browse Server” button is pressed in the Link tab of Image dialog.
config.filebrowserImageBrowseLinkUrl = “/ckeditor/pictures”;

// The location of an external file browser, that should be launched when “Browse Server” button is pressed in the Image dialog.
config.filebrowserImageBrowseUrl = “/ckeditor/pictures”;

// The location of a script that handles file uploads in the Image dialog.
config.filebrowserImageUploadUrl = “/ckeditor/pictures”;

// The location of a script that handles file uploads.
config.filebrowserUploadUrl = “/ckeditor/attachment_files”;

config.allowedContent = true;

// Toolbar groups configuration.
config.toolbar = [
{ name: ‘document’, groups: [ ‘mode’, ‘document’, ‘doctools’ ], items: [ ‘Source’] },
{ name: ‘clipboard’, groups: [ ‘clipboard’, ‘undo’ ], items: [ ‘Cut’, ‘Copy’, ‘Paste’, ‘PasteText’, ‘PasteFromWord’, ‘-‘, ‘Undo’, ‘Redo’ ] },
// { name: ‘editing’, groups: [ ‘find’, ‘selection’, ‘spellchecker’ ], items: [ ‘Find’, ‘Replace’, ‘-‘, ‘SelectAll’, ‘-‘, ‘Scayt’ ] },
// { name: ‘forms’, items: [ ‘Form’, ‘Checkbox’, ‘Radio’, ‘TextField’, ‘Textarea’, ‘Select’, ‘Button’, ‘ImageButton’, ‘HiddenField’ ] },
{ name: ‘links’, items: [ ‘Link’, ‘Unlink’, ‘Anchor’ ] },
{ name: ‘insert’, items: [ ‘Image’, ‘Flash’, ‘Table’, ‘HorizontalRule’, ‘SpecialChar’ ] },
{ name: ‘paragraph’, groups: [ ‘list’, ‘indent’, ‘blocks’, ‘align’, ‘bidi’ ], items: [ ‘NumberedList’, ‘BulletedList’, ‘-‘, ‘Outdent’, ‘Indent’, ‘-‘, ‘Blockquote’, ‘CreateDiv’, ‘-‘, ‘JustifyLeft’, ‘JustifyCenter’, ‘JustifyRight’, ‘JustifyBlock’ ] },
‘/’,
{ name: ‘styles’, items: [ ‘Styles’, ‘Format’, ‘Font’, ‘FontSize’ ] },
{ name: ‘colors’, items: [ ‘TextColor’, ‘BGColor’ ] },
{ name: ‘basicstyles’, groups: [ ‘basicstyles’, ‘cleanup’ ], items: [ ‘Bold’, ‘Italic’, ‘Underline’, ‘Strike’, ‘Subscript’, ‘Superscript’, ‘-‘, ‘RemoveFormat’ ] }
];

config.toolbar_mini = [
{ name: ‘paragraph’, groups: [ ‘list’, ‘indent’, ‘blocks’, ‘align’, ‘bidi’ ], items: [ ‘NumberedList’, ‘BulletedList’, ‘-‘, ‘Outdent’, ‘Indent’, ‘-‘, ‘Blockquote’, ‘CreateDiv’, ‘-‘, ‘JustifyLeft’, ‘JustifyCenter’, ‘JustifyRight’, ‘JustifyBlock’ ] },
{ name: ‘styles’, items: [ ‘Font’, ‘FontSize’ ] },
{ name: ‘colors’, items: [ ‘TextColor’, ‘BGColor’ ] },
{ name: ‘basicstyles’, groups: [ ‘basicstyles’, ‘cleanup’ ], items: [ ‘Bold’, ‘Italic’, ‘Underline’, ‘Strike’, ‘Subscript’, ‘Superscript’, ‘-‘, ‘RemoveFormat’ ] },
{ name: ‘insert’, items: [ ‘Image’, ‘Table’, ‘HorizontalRule’, ‘SpecialChar’ ] }
];
}

What I ended up with was this:

CKEDITOR.editorConfig = function( config )
{
// Toolbar groups configuration.
config.toolbar_mini = [
{ items: [ ‘Bold’, ‘Italic’, ‘Underline’, ‘Strike’] },
{ name: ‘paragraph’, groups: [ ‘list’, ‘indent’, ‘blocks’, ‘align’, ‘bidi’ ], items: [ ‘NumberedList’, ‘BulletedList’, ‘-‘, ‘Blockquote’ ] },
];
};

And then, I updated the toolbar configuration in my view: <%= f.input :text, label: “Lesson Text”, :as => :ckeditor, input_html: { :ckeditor => {:toolbar => ‘mini‘} %>

You can find additional configuration options for CKEditor here and here.


Testing Webhooks Locally

I wanted to be able to test webhooks locally so I didn’t have to keep deploying to code to test them.  The problem with testing webhooks is that the service (Stripe, Braintree, etc.) needs a URL to callback.  Ngrok is awesome, free software that allows you to test webhook callbacks locally by creating a tunnel that maps to your localhost address.

  1. Download ngrok
  2. Unzip the file
  3. Run the executable
  4. In the command prompt that comes up, type ‘ngrok http 3000’ (assuming that your local Rails app is running on port 3000 – i.e. localhost:3000), then enter
  5. ngrok should return some URLs that map to localhost:3000
  6. specify one of these URLs as the callback URL in your service’s settings

 


Changing Column to Add Precision and Scale

If you have to add precision and scale to a decimal field, here’s a sample migration:

 

class ChangeScale < ActiveRecord::Migration
def self.up
change_column :shirts, :price, :decimal, precision: 5, scale: 2
end

def self.down
change_column :shirts, :price, :decimal, :precision, :scale
end
end


Setting a Variable to a Specific Date

If you need to set a variable to a specific date, the way to do it is to use the Date.new method.

Date.new(year, month, day)

For example:

foo = Date.new(2013, 8, 31)