I study the open source project gitlab . It’s a well coding rails structure.
Here are some examples i think they are good.
Don’t query data in View/Helper
Avoid perform query in view/helper in Xdite’s Maintainable Rails View .
dashboard_controller.rb 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def show
@projects_limit = 30
@groups = current_user . authorized_groups . sort_by ( & :human_name )
@has_authorized_projects = @projects . count > 0
@projects_count = @projects . count
@projects = @projects . limit ( @projects_limit )
@events = Event . in_projects ( current_user . authorized_projects . pluck ( :id ))
@events = @event_filter . apply_filter ( @events )
@events = @events . limit ( 20 ) . offset ( params [ :offset ] || 0 )
@last_push = current_user . recent_push
respond_to do | format |
format . html
format . js
format . atom { render layout : false }
end
end
Group class methods
You could put all your class methods inside class << self
. Avoid to put self.
in each methods.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# method 1
class Ability
class << self
def allowed ( user , subject )
. . .
end
end
end
# method 2
class Ability
def self . allowed ( user , subject )
. . .
end
end
Always sexy validations
1
2
3
4
5
6
7
8
9
10
11
validates :name , presence : true
validates :email , presence : true , format : { with : /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ }
validates :bio , length : { within : 0 . . 255 }
validates :extern_uid , allow_blank : true , uniqueness : { scope : :provider }
validates :projects_limit , presence : true , numericality : { greater_than_or_equal_to : 0 }
validates :username , presence : true , uniqueness : true ,
exclusion : { in : Gitlab : :Blacklist . path },
format : { with : Gitlab : :Regex . username_regex ,
message : "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
validate :namespace_uniq , if : -> ( user ) { user . username_changed? }
Delgate method
Reference delegate in rails
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Post
belongs_to :user
delegate :name , :to => :user , :allow_nil => true , :prefix => true
delegate :name , :to => :user , :allow_nil => true , :prefix => "author"
end
class User
has_many :posts
end
# You can call it in Post instance
post = Post . find ( param [ :id ] )
post . user_name # return user's name
post . author_name # return user' name
Some basics i didn’t mention before.
object.map(&:foo)
Below are equivalent.
1
2
3
4
5
6
7
Base = Struct . new ( :name )
tag1 = Base . new ( 'hello' )
tag2 = Base . new ( 'bye' )
result = [ tag1 , tag2 ]. map { | tag | tag . name }
result = [ tag1 , tag2 ]. map ( & :name )
send
1
2
3
4
5
6
7
8
9
# These statements are equal
@person . age
@person . send :age
@person . age = 5
@person . send :age = , 5
@person . set_age ( 5 )
@person . send :set_age , 5
content_for ( yield )
Learned from Xdite’s Maintainable Rails View
layout.html.erb 1
2
3
4
5
6
7
8
# In your layout, you can put a sidebar with yield :sidebar
< div class = "main" >
< %= yield %>
</div>
<div class= "sidebar" >
<%= yield :sidebar %>
</div>
xxx.html.erb 1
2
3
4
# Use content_for :sidebar to render sidebar.
< %= content_for :sidebar do %>
<%= render "ad/foo" %>
<% end %>
change entire layout
Use layout
to make profiles page use profile layout not application layout
1
2
3
4
5
class ProfilesController < ApplicationController
layout 'profile'
. . .
end
redirect from localhost/project/yyy.git to localhost/project/yyy
application_controller.rb 1
2
3
4
5
6
def project
if id =~ /\.git\Z/
redirect_to request . original_url . gsub ( /\.git\Z/ , '' ) and return
end
. . .
end
Good gems
annotate : add comments to your ActiveRecord models/specs/routes..rb
awesome_print : pretty print your ruby objects
better_errors : better error page for rails
acts-as-taggable-on : a tagging plugin
rails_best_practices : code metric tool for rails