Yu-Chieh’s Blog (Y.C. Chang)

Ruby on Rails / Rubygems / FullStack / Git / Mac notes.

Change Default Web Server and Timezone for Heroku

  • add web server gem to your Gemfile
1
2
3
4
5
group :production do
  gem 'pg'
  gem 'rails_12factor'
  gem 'thin' # web server : thin
end
  • bundle it for updating your Gemfile.lock
1
2
3
$ bundle install
$ git add .
$ git commit -am 'bundle and update Gemfile.lock'
  • deploy to heroku
1
$ git push heroku master

done.

  • time zone config for heroku
1
$ heroku config:add TZ=Asia/Taipei

done.

  • for reset pg DB
1
$ heroku pg:reset DATABASE_URL --confirm heroku_app_name

Rails Tips: User Authentication Using Devise

  • create a demo project by rails
1
$ rails new topic
  • add gem ‘devise’ to Gemfile then bundle it.
1
2
3
4
# Gemfile
gem 'devise'

$ bundle
  • install into your project, generate user model and views
1
2
3
$ rails generate devise:install
$ rails generate devise User
$ rails generate devise:views
  • configure development.rb for action mailer setting
1
2
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
config.action_mailer.delivery_method = :smtp
  • configure application.rb for action mailer setting
1
2
3
4
5
6
7
8
9
10
ActionMailer::Base.smtp_settings = {

        :address        => 'smtp.gmail.com',
        :domain         => 'mail.google.com',
        :port           => 587,
        :user_name      => "your_gmail_account@gmail.com", #ENV['GMAIL_USERNAME'],
        :password       => "weakpass", #ENV['GMAIL_PASSWORD'],
        :authentication => 'login',
        :enable_starttls_auto => true
}
  • generate a scaffold for the topic resource and add registrations controller for overriding devise’s one
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ rails g scaffold topic title
$ rails g controller registrations

# in registrations_controller.rb

class RegistrationsController < Devise::RegistrationsController

  private

  def sign_up_params
    params.require(:user).permit(:name, :email, :password, :password_confirmation)
  end

  def account_update_params
    params.require(:user).permit(:name, :email, :password, :password_confirmation, :current_password)
  end
end

# modify route.rb
devise_for :users, controllers: { registrations: "registrations" }
root 'topics#index'

# add the following "before_action" to topics_conftroller.rb for forcing users logging in
before_action :authenticate_user!
done and enjoy it.

Rails App Deploy to Heroku : An Easy Way

Preparing step

  • install Postgres DB via brew
1
2
3
4
5
6
7
8
9
10
11
$ brew doctor
$ brew update
$ brew install postgresql

# if we want to run pg locally, we need to run the following instructions.

# To have launchd start postgresql at login:
ln -sfv /usr/local/opt/postgresql/*plist ~/Library/LaunchAgents

# Then to load and run postgresql immediately:
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist
1
2
$ heroku login
$ heroku create
  • Open the file called Gemfile in your text editor and find the line containing:
1
gem 'sqlite3'
  • Remove that line and replace it with:
1
2
3
4
5
6
7
8
group :development, :test do
  gem 'sqlite3'
end

group :production do
  gem 'pg'
  gem 'rails_12factor'
end
  • bundle install
1
$ bundle install --without production
  • git add . and git commit
1
2
$ git add .
$ git commit -m "Changed Gemfile for heroku"
  • finally, push to heroku
1
2
$ git push heroku master
$ heroku run rake db:migrate

Rails Tips: Rails G Scaffold for Reference Field

Rails scaffold generators are very smart! you can use belongs_to to quickly add relations. In the following example, I have 2 models products and product_types; Product_types belong to product and product has many product types.

1
2
3
4
5
6
7
8
9
$ rails g scaffold product name:string
$ rails g scaffold product_type name:string product:belongs_to

# You can also use :references
$ rails g scaffold product_type name:string product:references

# For more manually work, you can do it like this
$ rails g scaffold product_type name:string product_id:integer
# then add "belongs_to" in your ProductType model

This will generate the necessary columns, indexes and associations in your models.

RubyGems: Why Simple_form?

why use simple_form

  1. Required fields are marked with an * prepended to their labels.
  2. Simple Form also lets you overwrite the default input type it creates:
  3. You can overwrite the default label by passing it to the input method. You can also add a hint or even a placeholder. For boolean inputs, you can add an inline label as well.
  4. It is also possible to pass any html attribute straight to the input, by using the :input_html option.

[reference]

https://github.com/plataformatec/simple_form

Rails Tips: Link_to Helper for params.merge

  • To preserve the params of url I did this:
app/views/index.html.erb
1
2
3
4
...

<%= link_to 'Foot type', url_for(params.merge(foot_type_id: value)) %>
...
app/controllers/recipes_controller.rb
1
2
3
4
5
6
7
8
...
  def index
    @recipes = Recipe.where(nil)
    @recipes = @recipes.food_type_of(params[:food_type_id]) if (params[:food_type_id])
    @recipes = @recipes.food_preference_of(params[:food_preference_id]) if (params[:food_preference_id])
    @recipes = @recipes.cuisine_of(params[:cuisine_id]) if (params[:cuisine_id])
  end
...

alternative solutions

http://filterrific.clearcove.ca
http://www.lauradhamilton.com/how-to-filter-by-multiple-options-filterrific-rails
https://github.com/plataformatec/has_scope

[reference]

http://apidock.com/rails/v3.2.13/ActionView/Helpers/UrlHelper/url_for http://stackoverflow.com/questions/6625293/how-to-add-parameters-to-current-url-in-rails
http://www.justinweiss.com/blog/2014/02/17/search-and-filter-rails-models-without-bloating-your-controller/
http://guides.rubyonrails.org/active_record_querying.html#scopes

RubyGems: Brakeman and Rails_best_practices

brakeman : Ruby on Rails 專案安全性檢測工具

Brakeman is an open source vulnerability scanner specifically designed for Ruby on Rails applications. It statically analyzes Rails application code to find security issues at any stage of development.

rails_best_practices : Ruby on Rails 專案程式碼品質評測工具

rails_best_practices is a code metric tool to check the quality of rails codes.

installation (add those gems to your Gemfile)

1
2
3
4
5
6
group :development do
  gem "brakeman", require: false
  gem "rails_best_practices", require: false
end

# require: false => means that we don't want to run that gem when start rails server

usage (recommand using those tools before each commit)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ brakeman
# report screenshot
+SUMMARY+

+-------------------+-------+
| Scanned/Reported  | Total |
+-------------------+-------+
| Controllers       | 2     |
| Models            | 5     |
| Templates         | 6     |
| Errors            | 0     |
| Security Warnings | 0 (0) |
+-------------------+-------+

$ rails_best_practices
# report screenshot
Source Codes: |======================================================================================================================================|
rails_app/db/schema.rb:34 - always add db index (recipes => [food_type_id])
rails_app/db/schema.rb:34 - always add db index (recipes => [food_preference_id])
rails_app/db/schema.rb:34 - always add db index (recipes => [cuisine_id])
rails_app/app/views/recipes/index.html.erb:24 - law of demeter
rails_app/app/views/recipes/index.html.erb:25 - law of demeter
rails_app/app/views/recipes/index.html.erb:26 - law of demeter
rails_app/app/helpers/recipes_helper.rb:1 - remove empty helpers
rails_app/app/models/recipe.rb:8 - remove unused methods (Recipe#food_type_of)
rails_app/app/models/recipe.rb:9 - remove unused methods (Recipe#food_preference_of)
rails_app/app/models/recipe.rb:10 - remove unused methods (Recipe#cuisine_of)
rails_app/app/views/recipes/_form.html.erb:1 - replace instance variable with local variable
rails_app/app/views/recipes/_form.html.erb:2 - replace instance variable with local variable
rails_app/app/views/recipes/_form.html.erb:4 - replace instance variable with local variable
rails_app/app/views/recipes/_form.html.erb:7 - replace instance variable with local variable
rails_app/app/models/recipe.rb:8 - remove trailing whitespace

[reference]

http://brakemanscanner.org
http://rails101s.logdown.com/posts/247140-20-1-0-create-a-rails-project
https://github.com/railsbp/rails_best_practices

Rails Tips: List Models (Tables) (How-to)

1
2
3
4
5
6
7
8
9
10
11
$ rails c
 ActiveRecord::Base.connection.tables.each do |table_name|
  puts "\n" + table_name
  ActiveRecord::Base.connection.columns(table_name).each {|c| puts "- " + c.name + ": " + c.type.to_s + " " + c.limit.to_s}
 end

# or
 Model.column_names

# or
 Model
1
2
> ActiveRecord::Base.connection.tables # list all models retuen as an array
> ActiveRecord::Base.connection.columns(table_name) # list model(table) detail

Some Link_to Usage Tips

some tips for link_to helper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#in view/xxxx.html.erb

<%= link_to "LINK_NAME", xxx_path %>

<%= link_to "LINK_NAME", "LINK_URL", id: "ID_NAME", class: "CLASS_NAME" %>


# use it like a block
# 1
link_to "LINK_URL" do
  image_tag "IMAGE_FILE"
end

# 2
link_to xxx_path do
  image_tag "IMAGE_FILE"
end

Before_action v.s. Before_filter

To figureout what differece between before_action and before_filter, we should understand what difference between action and filter.

  1. An action is a method of a controller to which you can route to.
    For example, your user creation page might be routed to UsersController#new - new is the action in this route.

  2. Filters run in respect to controller actions - before, after or around them.
    These methods can halt the action processing by redirecting or set up common data to every action in the controller.

  3. Rails 4 –> _action
    Rails 3 –>
    _filter