7. The entire web
application/system/platform
runs as one single rails
application
(We are talking about really large systems.
Multiple different types of clients/functions)
15. Consistent UI
• Shared CSS/JS/Styleguide
• Common Helpers in Shared Gem
• Safely try new things
16. interface
All applications use the same base CSS/JS
Keep all the application the same style
<%= idp_include_js_css %>
# =>
<script src ="/assets/javascripts/frame.js" type="text/javascript"></script>
<link href="/assets/stylesheets/frame.css" media="screen" rel="stylesheet"
type="text/css" />
20. interface
Common Helpers: List table
well formatted sortable
with pagination customizable
21. interface
Common Helpers: List table (cont)
<%=
idp_table_for(@history_records,:sortable=>true,:customize =>
"history_records") do |item, col|
col.add :id, link_to(item.id, admin_history_record_path(item)),:order=>:id
col.build :duration, :waiting_time, :review_time
col.add :scenario, item.scenario_title, :order => :scenario_title
col.add :mark_spot_num
end
%>
22. interface
Development Lifecycle
1. Implement new View code/plugin in a
second application
2. Abstract into plugin using existing
“idp” helpers
3. Put it into main view gem
24. data
How do applications share data?
(remember: each app has its own data)
-“Read Only” Database Connections
- Services
- AJAX Loaded View Segments
25. data
Business example
user
purchase
course
learning process
26. data
Purchase App
Requirement: List course packages for
user to select to purchase
but
The course package data is stored in the “course”
application
28. data
Code
Model:
class CoursePackage < ActiveRecord::Base
acts_as_readonly :course
end
View:
<ul>
<% CoursePackage.all.each do |package| %>
<li><%= package.title %> <%= package.price %></li>
<% end %>
</ul>
29. data
Why doesn’t this break the rule of
loose coupling?
Model:
class CoursePackage < ActiveRecord::Base
acts_as_readonly :course
end
View:
<ul>
<% CoursePackage.all.each do |package| %>
<li><%= package.title %> <%= package.price %></li>
<% end %>
</ul>
30. data
acts_as_readonly in Depth
def acts_as_readonly(name, options = {})
config = CoreService.app(name).database
establish_connection config[Rails.env]
set_table_name(self.connection.current_database +
(options[:table_name]||table_name).to_s)
end
31. data
acts_as_readonly in Depth
def acts_as_readonly(name, options = {})
config = CoreService.app(name).database
establish_connection config[Rails.env]
set_table_name(self.connection.current_database +
(options[:table_name]||table_name).to_s)
end
32. data
Core service
class CoreService < ActiveResource::Base
self.site = :user
def self.app(app_name)
CoreService.find(app_name)
end
end
33. data
Centralized configuration
How does Core know all the configurations?
46. user
Features of User Service
• Registration/login
• Profile management
• Role Based Access Control
47. user
Access Control
Each Controller is one Node
* Posted to user service when app starts
48. user
Access Control
before_filter :check_access_right
def check_access_right
unless xml_request? or inner_request?
access_denied unless has_page_right?(params[:controller])
end
end
* Design your apps so access control can be by controller!
50. user
Step 1: User Auth
SSO
Shared
Session
Same Session
Store
51. user
Step 1: User Auth
config/initializers/idp_initializer.rb
ActionController::Base.session_store = :active_record_store
ActiveRecord::SessionStore::Session.acts_as_remote :user,
:readonly => false
52. user
Step 2: Access Control
Tell core its controllers structure
CoreService. reset_rights
def self.reset_rights
data = load_controller_structure
self.post(:reset_rights, :data => data)
end
53. user
Step 2: Access Control
before_filter :check_access_right
def check_access_right
unless xml_request? or inner_request?
access_denied unless has_page_right?(params[:controller])
end
end
54. user
Step 2: Access Control
has_page_right?
Readonly db conn again
55. user
Step 2: Access Control
class IdpRoleRight < ActiveRecord::Base
acts_as_readonly :user, :table_name => "role_rights"
end
def has_page_right?(page)
roles = current_user.roles
roles_of_page = IdpRoleRight.all(:conditions => ["path = ?",
page]).map(&:role_id)
(roles - (roles - roles_of_page)).size > 0
end
58. service
Support applications
• File
• Mail
• Comet service
59. File
Specify Class that
class Article < ActiveRecord::Base
Has Files has_files
end
Upload File in
Background to Idp_file_form
FileService
Store with
app_name,
model_name,
model_id
Use readonly
magic to easily @article.files.first.url
display
60. service
Comet
class ChatRoom < ActiveRecord::Base
acts_as_realtime
end
<%= realtime_for(@chat_room, current_user.login) %>
<%= realtime_data(dom_id, :add, :top) %>
@chat_room.realtime_channel.broadcast
(“hi world", current_user.login)
61. service
mail
Mail services
MailService.send(“test@idapted.com”, :welcome,
:user => “test”)
62. Host all in one domain
Load each rails app into a subdir, we
use Unicorn
unicorn_rails --path /user
unicorn_rails --path /studycenter
unicorn_rails --path /scenario
63. Host all in one domain
use Nginx as a reverse proxy
location /user {
proxy_pass http://rails_app_user;
}
location /studycenter {
proxy_pass http://rails_app_studycenter;
}
64. Host all in one domain
All you see is a uniform URL
www.eqenglish.com/user
www.eqenglish.com/studycenter
www.eqenglish.com/scenario
74. Measurement
• Critical and core task of single app should
not call services of others.
• One doesn’t need to know much about
others’ business to do one task (or develop).
• Independent Stories
79. Full Stack of Us
Develop environment:
• 4 mbp + 4 black apples + 1 linux
• textmate & netbeans
Servers:
• test: 2 physical pc with Xen serving 10
virtual servers
• production: 2 (China) + 5(US)
80. Full Stack of Us
Web Server:
• nginx + unicorn
Rails:
• Rails version 2.3.4
• Ruby version: 1.8.7
81. Full Stack of Us
Plugins:
• exception_notification
• will_paginate
• in_place_editor_plus
• acts_as_list
• open_flash_chart
• Spawn + workling
82. Full Stack of Us
Gems:
• rspec
• factory_girl
• thinking-sphinx
DB:
• mysql
Cache:
• memcache
83. Full Stack of Us
Test:
• rspec + factory_girl
• Autospec
Deploy:
• webistrano
84. Full Stack of Us
Team Build:
• board
• code review
• tea break
• retreat
85. Join Us
If you are:
• smart
• creative
• willing to do great things with great people
• happen to know JS/Flex/Rails
Send whatever can prove your ability to:
tech-team-jobs@idapted.com