Categories
Compatibility issues HTML

HTML: coding email newsletters

Golden rules:
1) Make sure width and height is set in each td and img tags in the email: not on the table! but on each cell.
2) Every image is set to display:block. Also, if relevant, put an alt attribute as 40% of email readers won’t download the actual image. Also, whenever possible, user https:// for the links to avoid being flagged as spam.
3) Every link is set to have no border and no outline. target=”_blank” all of them. Also, whenever possible, user https:// for the links to avoid being flagged as spam.
4) Cell padding and cellspacing is removed from each table as much as possible:

5) The layout is broken up in a series of rows, and each row with complex images / data will also be a nested table 6) All styling is done inline. It is a pain, agree. Here’s a tool to make it easier: http://premailer.dialect.ca/ 7) Margin and padding are inconsistently applied across email clients: again, your best friend are tables and cells with widths and heights defined. 8) Background color for the entire email can be set if you put it as follows:

[other nested tables with your content here]

9) Whitespace does matter! If you have spaces or line spaces between rows and cells, they may be interpreted funky by some email clients, avoid them!

If you don’t want to “reinvent the wheel”, and spend lots of time and effort on the emails yourself, use already built and already tested templates:
http://mailchimp.com/resources/html-email-templates/
http://www.campaignmonitor.com/templates/

Troubleshooting:

Outlook 2007 / Outlook 2010: You see only background color where there is supposed to be content. Solution: remove bgcolor=”#[color]” property.

IOS: Avoid auto-formatting of dates and phones:

If your HTML looks like this:

will cease<br> operations <span class=’ios-avoid-format’>on June 1, 2012</span><span></span>.

The CSS that will make this ok in iphone / ipad is:

@media only screen and (device-width: 768px) and (orientation:portrait){
span.ios-avoid-format{
display:none;
}
span.ios-avoid-format + span:after{
content:”on June 1, 2012″;
}
}

Great resources for your email needs:

litmus.com — Essencial for testing

Mailchimp — Great and free for certain number of users on your list

http://premailer.dialect.ca/ — Inline your CSS styles, fast and easy

Categories
mysql Web optimization

Mysql: increase the size of innodb_buffer_pool_size

By putting this on your mysql config file:

[mysqld]
innodb_buffer_pool_size = 2G

In dedicated db machines, you can set this to close to 80% of the available memory. This will avoid disk writes and speed up things in general.

The mysql configuration file is on :

/etc/my.cnf (usually)

Restaring mysql, and barabum barabim

The typical error message you get when this is too small is:

Mysql::Error: The total number of locks exceeds the lock table size:

Categories
Rails

Ruby On Rails: pagination

Use will_paginate gem (include in your Gemfile):
gem ‘will_paginate’, ‘3.0.pre2’

Code example once the gem is setup:

<%= will_paginate %>

      <% @users.each do |user| %>

    • <%= gravatar_for user, :size => 30 %> <%= link_to user.name, user %>

<% end %>

<%= will_paginate %>

Categories
Rails

Ruby On Rails: cookies

cookies[:remember_token] = { :value => user.id, :expires => 20.years.from_now.utc }

A “remember token” cookie is created, you can also do the 20 years part as:

cookies.permanent[:remember_token] = user.remember_token

cookies.permanent.signed[:remember_token] = [user.id, user.salt]

Obscures the real user.id with the salt, for security purposes

Retrieving stuff from cookies:

User.find_by_remember_token(cookies[:remember_token]) // This will query for a user with remember_token

Categories
Rails

Ruby On Rails: security

Making sure passwords and other form data are hidden. Hidden meaning not showing up on the log file.

Go inside the config/application.rb file, and add the following line (if not there):


# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]

end

This will ensure your sensitive password form field don’t end up showing in the log file

Categories
Rails

Ruby On Rails: forms

In the example below we are passing a @user variable, but you can also pass something like this:

<%= form_for User.new, :url => { :controller => “users”, :action => “create” }, :html => {:class => “whatever_class_needed”} do |f| %>

And now, the example:

<%= form_for(@user) do |f| %><%= f.label :name %>
<%= f.text_field :name %><%= f.label :email %>
<%= f.text_field :email %><%= f.label :password %>
<%= f.password_field :password %><%= f.label :password_confirmation, “Confirmation” %>
<%= f.password_field :password_confirmation %>

<%= f.submit “Create my account”, class: “btn btn-large btn-primary” %>
<% end %>

If you want to also include the error messages:
<%= render ‘shared/error_messages’ %>
In your shared directory, you have a partial that handles that:
<% if @user.errors.any? %>
<div id=”error_explanation”>
<div class=”alert alert-error”>
The form contains <%= pluralize(@user.errors.count, “error”) %>.
</div>
<ul>
<% @user.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Where @user is the controller variable driving your form
If you need to style the error messages differently (than the default red), you can modify the following stylesheet:
app/assets/stylesheets/scaffold.css.scss
Categories
Rails

Ruby On Rails: manually generating a migration. Enforce uniqueness of a database column

$ rails generate migration add_email_uniqueness_index

It will create the following file:
db/migrate/_add_email_uniqueness_index.rb

In this case, we are adding an index to the email address column, to guarantee its uniqueness, so the file will look like this:

class AddEmailUniquenessIndex < ActiveRecord::Migration
def self.up
add_index :users, :email, :unique => true
end
def self.down
remove_index :users, :email
end
end

Now that we are in the subject of uniqueness, even as we are enforcing it by adding the :unique => true directly as a db constrain, we should in fact enforce this in the model level instead. By adding the following lines:

validates_uniqueness_of :my_column_name

If you do that on your model, you get the benefits of validation, instead of a db error you would have to handle

Another example:
$ rails generate migration add_password_to_users encrypted_password:string
By adding “_to_users” we are indicating rails what table we want this added to, the generated code looks as below:
class AddPasswordToUsers < ActiveRecord::Migration
def self.up
add_column :users, :encrypted_password, :string
end
def self.down
remove_column :users, :encrypted_password
end
end

RAILS 4 UPDATE: instead of self.up and self.down, we have the word “change” now

Categories
Rails

Ruby on Rails: testing

$ rake db:test:prepare

Ensures that the db in development environment is propagated to the test environment.

To have pending RSpec tests, you do the following:
require ‘spec_helper’
describe User do
pending “add some examples to (or delete) #{__FILE__}”
end

If you want to prepare data prior to testing:
before(:each) do
@attr = { :name => “Example User”, :email => “user@example.com” }
end

When checking for validity of records, you can do it as:
no_name_user.should_not be_valid
or
no_name_user.valid?.should_not == true

With the code below, we are testing that a certain object has a certain attribute (with responds_to):
it “should have an encrypted password attribute” do
@user.should respond_to(:encrypted_password)
end

Adding factories to create testing objects can save a lot of time, there is a gem that can be added to your Gemfile, in the test environment to do this:
group :test do
. . .
gem ‘factory_girl_rails’, ‘1.0’
end

Once the gem is install (bundle install), you can create the following file:
spec/factories.rb
And here’s a sample content:
# By using the symbol ‘:user’, we get Factory Girl to simulate the User model.
Factory.define :user do |user|
user.name “Michael Hartl”
user.email “mhartl@example.com”
user.password “foobar”
user.password_confirmation “foobar”
end

So now, factory objects of the order :user can be created for testing purposes as follows:
@user = Factory(:user)

Here’s an example of a Factory that contains associations between two different objects:
# By using the symbol ‘:user’, we get Factory Girl to simulate the User model.
Factory.define :user do |user|
user.name “Michael Hartl”
user.email “mhartl@example.com”
user.password “foobar”
user.password_confirmation “foobar”
end

Factory.sequence :email do |n|
“person-#{n}@example.com”
end

Factory.define :micropost do |micropost|
micropost.content “Foo bar”
micropost.association :user
end

If you want to clear the test database of any user data still hanging there, use:
$ rake db:reset

Rails 4 update

Example of a model test (creating an article). The test resides in /test/models/

require 'test_helper'

class ArticleTest < ActiveSupport::TestCase
  test "should create article" do
    article = Article.new

    article.user  = users(:eugene)
    article.title = "Test article"
    article.body  = "Test body"

    assert article.save
  end
end

Some of the most used available assertions:

assert(boolean, message=nil)
assert_block(message="assert_block failed.") do ... end
assert_equal(expected, actual, message=nil)
assert_in_delta(expected_float, actual_float, delta, message="")
assert_instance_of(klass, object, message="")
assert_kind_of(klass, object, message="")
assert_match(pattern, string, message="")
assert_nil(object, message="")
assert_no_match(regexp, string, message="")
assert_not_equal(expected, actual, message="")
assert_not_nil(object, message="")
assert_not_same(expected, actual, message="")
assert_nothing_raised(*args) do ... end
assert_nothing_thrown(message="") do ... end
assert_operator(object1, operator, object2, message="")
assert_raise(expected_exception_klass, message="") do ... end
assert_respond_to(object, method, message="")
assert_same(expected, actual, message="")
assert_send(send_array, message="")
assert_throws(expected_symbol, message="") do ... end

To run it:

$ rake test:models

In order to generate a template for integration testing:

$rails generate test_unit:integration UserStories

To run that particular test:
$ruby -Itest test/integration/user_stories_test.rb

And, to run the full test suite:
$rake

or

$bundle exec rspec [name of the spec you want to run, optional]

Categories
Rails

Ruby On Rails: utilities and console commands

run rails as in prod mode (in your dev env)

$ bundle exec rake assets:precompile
$ bundle exec rake db:migrate RAILS_ENV=production

change this line inside: config/environments/production.rb

  config.serve_static_files = true

run your server as:

SECRET_KEY_BASE=`rake secret` rails s -e production -b 0.0.0.0

the -b part is only if you are running inside vagrant and port forwarding.

console

$heroku console # brings the console in the production site if hosted in heroku…. amazingly easy to access prod!

$ rails console –sandbox
This starts the console, and rollback any changes we make to the data once we exit the console

$ rails console test
Loads the test environment in the console (instead of the default development environment)

$ tail -f log/development.log
Tailing the development log

Basic console commands:

>> User.column_names # Describe the model’s attributes (or db column names)
>> User.new # Creates a new user object
>> user = User.new(:name => “Michael Hartl”, :email => “mhartl@example.com”) => # >> user.save # Save the object specified
>> user.name # access a specific property of the object
>> User.create(:name => “A Nother”, :email => “another@example.org”) # same as a user.New and a user.save
>> foo.destroy # destroy a created object, but the created object will still in memory (see below)
>> foo => # #Still gave you something even after destroy

>> User.find(1) # Find user with id 1
>> User.find_by_email(“mhartl@example.com”) # Find user by email (or any other specific attributes)
>> User.first # Find the first user in DB
>> User.all # Returns all usrs

>> user.email = “mhartl@example.net” #Updating a user’s property, and then do user.save
>> user.update_attributes(:name => “The Dude”, :email => “dude@abides.org”) #Update several attr at once, and also performs a user.save at the end, only attributes indicated on the object as attr_accessible can be updated this way

>> user.errors.full_messages # If there were errors when saving the data, they will be contained here

If you want to access some of your helper methods while in the console:

>include ActionView::Helpers::TextHelper  // Now you can use them

You can also use raw sql statements to interact with your database, by loading an sql console the following way:

rails dbconsole
Categories
Rails

Ruby On Rails: models

$ rails generate model User name:string email:string
invoke active_record
create db/migrate/_create_users.rb
create app/models/user.rb invoke rspec
create spec/models/user_spec.rb

Note: Make sure you assign what attributes of your model will be accessible for edit, otherwise Ruby assumes all of them are, and this can be a security hole:

class User < ActiveRecord::Base
attr_accessible :name, :email

Note: on rails 4.1, the attr_accessible method moved to the controllers. The reason being: some apps run into issues where different models wanted to use attr_accessible params in different ways, so these make more sense to be at the controller level.

email_regex = /A[w+-.]+@[a-zd-.]+.[a-z]+z/i
validates(:name, :presence => true, :length => { :maximum => 50 })
validates :email, :presence => true, :format => { :with => email_regex }, :uniqueness => {:case_sensitive => false}
validates :password, :presence => true, :confirmation => true, :length => { :within => 6..40 }

end

The above creates getters and setters for the attributes name and email in that specific model.

Validates adds automatic data validation to the model. Notice how the email address validation takes a regular expression to do this. Notice how password and password confirmation fields are generated in the same line

In order to view and interact with the new model, we need a controller, router and view files, like the ones below:
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
end

def new
@title = “Sign up”
end
end

SampleApp::Application.routes.draw do
resources :users
match ‘/signup’, :to => ‘users#new’
. . .
end

Note: if you do the above in the route, remove: get “users/new”

Inside the models, if you specify the following, your queries will follow the order specified:

default_scope lambda { order('categories.name') }

If you don’t want to be too broad, and you want to be able to choose your scope, you can enhance your model with a scope:

scope :published, lambda { where("articles.published_at IS NOT NULL") }
  scope :draft, lambda { where("articles.published_at IS NULL") }
  scope :recent, lambda { published.where("articles.published_at > ?",
1.week.ago.to_date)}
  scope :where_title, lambda { |term| where("articles.title LIKE ?", "%#{term}%") }

And then, you can do queries like:
Article.published
Article.where_title(“Active”)

If you want to make some of the model’s methods static, so they can be called off the Model’s class (instead of from an instance of the model), you need to use the “self” key. For example, to make the “authenticate” method available off User.authenticate(), you can specify it inside the model as follows:

def self.authenticate(email, password)
user = find_by_email(email)
return user if user && user.authenticated?(password)
end