2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

114
百媒體網站 wordpress rails Ronald Hsu (hothero) Technical Director, backer-founder.com http://blog.hothero.org @hothero slide: http://backme.tw/ref/wp-rails

Transcript of 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Page 1: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

百⼤大媒體網站 從 wordpress 到 rails 的

⼤大⼩小事Ronald Hsu (hothero)

Technical Director, backer-founder.com

http://blog.hothero.org

@hothero

slide: http://backme.tw/ref/wp-rails

Page 2: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

What’s the talk about?• No diabolic tricks and wicked craft

• A year experience sharing

• Goes through our practice

• You will know more gems

• You will know what media websites care about most

• You will know how to handle larger traffic for media websites

• Nothing funny

Page 3: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

What’s the talk about?• No diabolic tricks and wicked craft

• A year experience sharing

• Goes through our practice

• You will know more gems

• You will know what media websites care about most

• You will know how to handle larger traffic for media websites

• Nothing funny

Page 4: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Backer-Founder

• First and leading crowdfunding consulting agency in Taiwan

• Has carried out 40 projects to domestic and abroad

• Raised over $7 million in 11 months since its establishment in October 2014.

Page 5: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Backer-Founder

Page 7: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Backer-Founder

http://xkcd.com/323/

Page 8: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Backer-Founder

Page 9: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

TNL

• A group of people who are dissatisfied with the existing media environment and want to make a difference.

• We aspire to build a media that provides not only facts, but also diverse perspectives.

Page 10: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

X

Page 11: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

X

Page 12: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Our Progress & GoalBackend

+DB Schema

Frontend

Page 13: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Wordpress• WordPress is a free and open-source content

management system (CMS) based on PHP and MySQL.

• Features include a plugin architecture and a template system.

• WordPress was used by more than 23.3% of the top 10 million websites as of January 2015.

• Initial release May 27, 2003 (12 years ago)

http://www.wikiwand.com/en/WordPress

Page 14: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Wordpress

Page 15: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Wordpress

Page 16: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Wordpress

Page 17: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Wordpress

Page 18: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Wordpress

Page 19: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Wordpress

• More than 30000 commits

• 23+ contributors

• 127+ version releases

• Nearly 500,000 lines of code, which contains nearly 300,000 lines of php code

https://github.com/wordpress/wordpress

Page 20: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

But why?

Page 21: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Three Main Issues

Customization Difficulty

Few Wordpress Developer in T.W.

Performance Issue

Page 22: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Three Main Issues

Customization Difficulty

Few Wordpress Developer in T.W.

Performance Issue

Page 23: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Three Main Issues

Customization Difficulty

Few Wordpress Developer in T.W.

Performance Issue

Page 24: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Three Main Issues

Customization Difficulty

Few Wordpress Developer in T.W.

Performance Issue

Page 25: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Three Main Issues

Customization Difficulty

Few Wordpress Developer in T.W.

Performance Issue

Page 26: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

So...we start to use rails

Page 27: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Our Progress & GoalBackend

+DB Schema

Frontend

Page 28: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Wordpress DB Schema• posts, pages, custom

post types, attachments, links, navigation menu items, categories, tags, custom taxonomies, taxonomy terms, post metadata, widgets, options, users, hardcoded content, third party content

http://goo.gl/Tbbpfr

Page 29: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Wordpress Structure

posts

pages

custom post typespost metadata

options

categories

users

attachments taxonomy terms

tags

navigation menu items

widgets

custom taxonomieswp_posts wp_terms

wp_term_taxonomy

wp_post_meta

wp_options

wp_users

wp_linkslinks

Page 30: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Wordpress Structure

posts

pages

custom post typespost metadata

options

categories

users

attachments taxonomy terms

tags

navigation menu items

widgets

custom taxonomieswp_posts wp_terms

wp_term_taxonomy

wp_post_meta

wp_options

wp_users

wp_linkslinks

PostEditing

Tag/Category

Page 31: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

General in Post Editing

has_many

has_manyIt means static

contentPost

Attachment

Revision

Page

Page 32: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

posts

pages

custom post

attachments

navigation menu

wp_posts

But in wordpress …

wp_posts revisionsattachmentsnav menu items

Page 33: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

But in wordpress …• All of those we mentioned before are in

only one table.

• Also include custom post types, links, navigation menu items!!!

post_type•post •page •revision •attachment •nav_menu_item •…

Page 34: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

In Rails 1 has_many :attachments, -> { where(post_type: 2 "attachment") }, 3 foreign_key: 4 "post_parent", 5 class_name: 6 "Post" 7 has_many :revisions, -> { where(post_type: 8 "revision") }, 9 foreign_key: 10 "post_parent", 11 class_name: "Post"

Page 35: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

postspages

custom post types

attachments

navigation menu items

wp_posts

Tag / Categorycategories

taxonomy terms

tags

wp_terms

Page 36: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Wordpress DB Schema

Page 37: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

In practice

• Category

• wp_term_taxonomy.taxonomy: category

• wp_terms.name: Politics

• Tag

• wp_term_taxonomy.taxonomy: post_tag

• wp_terms.name: FireChat

Page 38: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

In Rails 1 # models/w_post.rb 2 has_many :w_terms, through: : 3 w_term_relationships, foreign_key: "term_id" 4 has_many :w_term_relationships, foreign_key: 5 "object_id" 6 has_many :tags, 7 -> { where("#{WTermTaxonomy.table_name}.taxonomy = 'post_tag'") }, 9 through: :w_terms, source: :w_term_taxonomy, 10 class_name: "WTerm" 11 has_many :categories, 12 -> { where("#{WTermTaxonomy.table_name}.taxonomy = 'category'") }, 14 through: :w_terms, source: :w_term_taxonomy, 15 class_name: "WTerm" 16 17 # models/w_term_relationship.rb 18 belongs_to :w_term_taxonomy, foreign_key: 19 "term_taxonomy_id" 20 has_one :w_term, :through => :w_term_taxonomy

Page 39: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

In Rails 1 # models/w_post.rb 2 has_many :w_terms, through: : 3 w_term_relationships, foreign_key: "term_id" 4 has_many :w_term_relationships, foreign_key: 5 "object_id" 6 has_many :tags, 7 -> { where("#{WTermTaxonomy.table_name}.taxonomy = 'post_tag'") }, 9 through: :w_terms, source: :w_term_taxonomy, 10 class_name: "WTerm" 11 has_many :categories, 12 -> { where("#{WTermTaxonomy.table_name}.taxonomy = 'category'") }, 14 through: :w_terms, source: :w_term_taxonomy, 15 class_name: "WTerm" 16 17 # models/w_term_relationship.rb 18 belongs_to :w_term_taxonomy, foreign_key: 19 "term_taxonomy_id" 20 has_one :w_term, :through => :w_term_taxonomy

Page 40: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

If you need to know more…

• http://codex.wordpress.org/Database_Description

• http://code.tutsplus.com/tutorials/understanding-and-working-with-data-in-wordpress--cms-20567

Page 41: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

And we made a gem

• wpdb_activerecord: https://github.com/hothero/wpdb_activerecord

• It’s a ORM wrapper for the WordPress database, using ActiveRecord.

Page 42: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb_activerecord 1 # Gemfile 2 gem "wpdb_activerecord" 3 4 # Post 5 WPDB::Post.all # Get all posts 6 @post = WPDB::Post.find(75) 7 @post.tags 8 @post.attachments # No matter what type 9 @post.revisions 10 @post.author 11 12 # Term 13 WPDB::Term.tag # get all tags 14 WPDB::Term.category # get all categories

Page 43: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb_activerecord - advanced

1 # config/wpdb_activerecord.yml 2 WPDB_PREFIX: "cgjbugpbs_" # the table of WPDB::Post is cgjbugpbs_posts, not wp_posts 4 WPDB_USER_CLASS: "WUser" 5 6 # models/w_user.rb 7 class WUser < WPDB::User 8 def hello 9 puts "world" 10 end 11 end 12 13 # usage 14 @author = WPDB::Post.find(25).author 15 @author.class_name # will get WUser, not WPDB:: 16 User 17 @author.hello # world

Page 44: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb - installation

Page 45: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb - installation

Page 46: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb - installation

Page 47: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb - installation

Page 48: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb - installation

Page 49: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb -usage

Page 50: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb -usage

Page 51: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb -usage

Page 52: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb -usage

Page 53: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb -usage

Page 54: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb -usage

Page 55: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb -usage

Page 56: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb -usage

Page 57: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Our Progress & GoalBackend

+DB Schema

Frontend

Page 58: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

wpdb_activerecord

Server Side

Visitors

i0.wp.com/…

Page 59: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Cloudflare - Page Rules

Page 60: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

And we done

pcu 6000 ⬆ NT$5000 ⬇

Monthly Data • 7 million pageview ⬆ • 1.2 hundred million requests ⬆

• 4 million UU ⬆

Page 61: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

2015/02

Page 62: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Our Progress & GoalBackend

+DB Schema

Frontend

Page 63: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

CMS Admin

Edit Flow

Media Gallery

Globalize

Cronjob

Page 64: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

editflow.org• Edit Flow gives you custom statuses, a calendar, editorial comments, and

more, all to make it much easier for your team to collaborate within WordPress.

• Calendar

• Custom Statuses

• Editorial Comments

• Editorial Metadata

• Notifications

• Story Budget

• User Groups

Page 65: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Editor Structure

Author

SeniorEditor

ChiefEditor

ready to review

ready to check publish

Normal Flow

Editor

Page 66: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Edit Flow

Calendar

Custom Statuses

Notifications

Page 67: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Editorial Comments• Threaded commenting in the admin for private

discussion between writers and editors.

Page 68: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Editorial Comments• Use this gem: acts_as_commentable

• Polymorphic Associations

1 commentable = Post.create 2 comment = commentable.comments.create 3 comment.title = "First comment." 4 comment.comment = "This is the first comment." 5 comment.save

Page 69: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

What’s the Polymorphic Associations

• Assume a situation

• An employee has many pictures

• A Product has many pictures

• And each of those pictures have owned information detail.

Page 70: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

What’s the Polymorphic Associations

• In general: two relationship tables to associate objects and pictures

EmployeeProduct

Employee_ Relationship

employee_idpicture_id

Product_ Relationship

product_idpicture_id

Picture

Page 71: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

What’s the Polymorphic Associations

• Level up: an additional table to associate Employee

Product

ObjectRelationship

object_idpicture_id

Picture

Page 72: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

What’s the Polymorphic Associations

• Polymorphic Associations

Employee

Product

Picture

imageable_idimageable_type

will be: * Employee * Product

Page 73: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

What’s the Polymorphic Associations

• Practice in Rails.

Page 74: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

What’s the Polymorphic Associations

• In migration

Page 75: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

editflow.org• Edit Flow gives you custom statuses, a calendar, editorial comments, and

more, all to make it much easier for your team to collaborate within WordPress.

• Calendar

• Custom Statuses

• Editorial Comments

• Editorial Metadata

• Notifications

• Story Budget

• User Groups

Page 76: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Story Budget• View all of your upcoming posts in a more traditional story

budget view, and hit the print button to take it to your planning meeting.

Page 77: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Search Design In General• In general, we maybe use many conditions to match different

situation. 1 def search 2 @posts = Post.send(params[:scope]) 3 if params.key?(:author_id) 4 @posts = @posts.where(author_id: params[: 5 author_id]) 6 end 7 if params.key?(:post_type) 8 @posts = @posts.where(post_type: params[: 9 post_type]) 10 end 11 if params.key?(:start_date) || params.key?(: 12 end_date) 13 @posts = @posts.where(updated_at: params[: 14 start_date]..params[:end_date]) 15 end 16 # ... 17 end

Page 78: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Search Design In General• In general, we maybe use many conditions to match different

situation. 1 def search 2 @posts = Post.send(params[:scope]) 3 if params.key?(:author_id) 4 @posts = @posts.where(author_id: params[: 5 author_id]) 6 end 7 if params.key?(:post_type) 8 @posts = @posts.where(post_type: params[: 9 post_type]) 10 end 11 if params.key?(:start_date) || params.key?(: 12 end_date) 13 @posts = @posts.where(updated_at: params[: 14 start_date]..params[:end_date]) 15 end 16 # ... 17 end

https://github.com/activerecord-hackery/

ransack

Page 79: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Ransack - View Helper 1 <%= search_form_for @q do |f| %> 2 # Search if the name field contains... 3 <%= f.label :name_cont %> 4 <%= f.search_field :name_cont %> 5 6 # Search if an associated articles.title 7 starts with... 8 <%= f.label :articles_title_start %> 9 <%= f.search_field :articles_title_start %> 10 11 # Attributes may be chained. Search multiple 12 attributes for one value... 13 <%= f.label : 14 name_or_description_or_email_or_articles_t 15 itle_cont %> 16 <%= f.search_field : 17 name_or_description_or_email_or_articles_t 18 itle_cont %> 19 20 <%= f.submit %> 21 <% end %>

name_cont

Page 80: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Ransack - View Helper 1 <%= search_form_for @q do |f| %> 2 # Search if the name field contains... 3 <%= f.label :name_cont %> 4 <%= f.search_field :name_cont %> 5 6 # Search if an associated articles.title 7 starts with... 8 <%= f.label :articles_title_start %> 9 <%= f.search_field :articles_title_start %> 10 11 # Attributes may be chained. Search multiple 12 attributes for one value... 13 <%= f.label : 14 name_or_description_or_email_or_articles_t 15 itle_cont %> 16 <%= f.search_field : 17 name_or_description_or_email_or_articles_t 18 itle_cont %> 19 20 <%= f.submit %> 21 <% end %>

articles_title_start

Page 81: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Ransack - View Helper 1 <%= search_form_for @q do |f| %> 2 # Search if the name field contains... 3 <%= f.label :name_cont %> 4 <%= f.search_field :name_cont %> 5 6 # Search if an associated articles.title 7 starts with... 8 <%= f.label :articles_title_start %> 9 <%= f.search_field :articles_title_start %> 10 11 # Attributes may be chained. Search multiple 12 attributes for one value... 13 <%= f.label : 14 name_or_description_or_email_or_articles_t 15 itle_cont %> 16 <%= f.search_field : 17 name_or_description_or_email_or_articles_t 18 itle_cont %> 19 20 <%= f.submit %> 21 <% end %>

name_or_description_or_email_or_articles_title_cont

Page 82: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Ransack - Controller

1 def index 2 @q = Person.ransack(params[:q]) 3 @people = @q.result(distinct: true) 4 end

Page 83: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Ransack - Controller

1 def index 2 @q = Person.ransack(params[:q]) 3 @people = @q.result(distinct: true) 4 end

Page 84: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

In Practice

q[status_scope]

q[author_id_eq]

q[post_type_eq]

q[author_name_cont]

q[updated_at_gteq] - q[updated_at_lteq]

Page 85: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

editflow.org• Edit Flow gives you custom statuses, a calendar, editorial comments, and

more, all to make it much easier for your team to collaborate within WordPress.

• Calendar

• Custom Statuses

• Editorial Comments

• Editorial Metadata

• Notifications

• Story Budget

• User Groups

Page 86: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

User Groups• Keep your users organized by department or function.

Page 87: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Editor Structure

Author

SeniorEditor

ChiefEditor

Editor

Page 88: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Maybe DB SchemaUser Author Editor Admin

orUser

user_type

Page 89: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

STI (Single-table inheritance)class User < ActiveRecord::Baseend

class Author < User enum role: [:normal, :blogger] def publish # ex: only author can use endend

class Editor < User enum role: [:editor, :senior_editor, :chief]end

class Admin < Userend

User

typetype: rails reserved word

Page 90: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

STI with Priority Problem

• STI is unfit for priority feature.

• Chief Editor > Senior Editor > Editor > Author

• Enum-design is more fit. 1 class User < ActiveRecord::Base 2 enum role: [:normal, :blogger, :editor, :senior_editor, :chief] 4 end

Page 91: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Other parts

• Except edit-flow, there are some more features

• takeover & editing lock

• media gallery

• globalize

Page 92: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

A situation

Author

Editorwanna edit

Page 93: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

takeover & editing lock

• Use this gem: message_bus

• MessageBus implements a Server to Server channel protocol and Server to Web Client protocol (using polling or long-polling)

Page 94: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

• We use current_editor_id field as lock in post.

• Subscribe a channel for takeover when start editing in front-end.

• Publish a message to the channel when someone wanna edit.

takeover & editing lock

1 MessageBus.start(); 2 MessageBus.callbackInterval = 500; 3 MessageBus.subscribe("/posts/<%= @post.id %>/takeover/request", 4 function(msg){ 5 unlock_post_and_auto_save(); 6 window.location = "<%= posts_path %>"; 7 });

1 MessageBus.publish(“/posts/#{post.id}/takeover/request”, username: user.name)

Channel

Page 95: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Media Gallery

Page 96: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Media Gallery - Tricks

Browsers don't allow file uploads via XMLHttpRequest

(aka XHR) for security reasons.

Page 97: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

General in jQuery• Hijack the forms submit event to execute our custom

iFrame-method function

• Submit the form to the iFrame normal-style (non-AJAX)

• Copy the response content from the iFrame back into the parent window.

http://www.alfajango.com/blog/ajax-file-uploads-with-the-iframe-method/

Page 98: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

remotipart• Use this gem: remotipart

• Remotipart is a Ruby on Rails gem enabling AJAX file uploads with jQuery in Rails 3 and Rails 4 remote forms.

1 # Gemfile 2 gem "remotipart" 3 4 # js 5 //= require jquery.remotipart

Page 99: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Globalize

Page 100: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

globalize• Use this gem: globalize

• Each locale have their owned tags & revisions

1 # config/initializers/post_translation.rb 2 Post::Translation.module_eval do 3 acts_as_ordered_taggable 4 has_paper_trail only: [:content, :title, : 5 excerpt] 6 end

Page 101: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Mobile APP• http://apps.thenewslens.com/

Page 102: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

API Design In Generalclass ApiController < ApplicationController def all # get review & news type post case params[:post_type] when "new" # latest when "hot" # hot end end

def review case params[:post_type] when "new" when "hot" end endend

def news case params[:post_type] when "new" when "hot" end end

Page 103: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

has_scope• Use this gem: has_scope

• In model

1 class Graduation < ActiveRecord::Base 2 scope :featured, -> { where(:featured => true) 3 } 4 scope :by_degree, -> degree { where(:degree => 5 degree) } 6 scope :by_period, -> started_at, ended_at { 7 where("started_at = ? AND ended_at = ?", 8 started_at, ended_at) } 9 end

Page 104: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

has_scope• You can use those named scopes as filters by declaring

them on your controller and just need to call apply_scopes to an specific resource. 1 class GraduationsController < 2 ApplicationController 3 has_scope :featured, :type => :boolean 4 has_scope :by_degree 5 has_scope :by_period, :using => [:started_at, 6 :ended_at], : 7 type => :hash 8 9 def index 10 @graduations = apply_scopes(Graduation).all 11 end 12 end

Page 105: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

has_scope• You can use those named scopes as filters by declaring

them on your controller and just need to call apply_scopes to an specific resource. 1 class GraduationsController < 2 ApplicationController 3 has_scope :featured, :type => :boolean 4 has_scope :by_degree 5 has_scope :by_period, :using => [:started_at, 6 :ended_at], : 7 type => :hash 8 9 def index 10 @graduations = apply_scopes(Graduation).all 11 end 12 end

/graduations?featured=true

Page 106: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

has_scope• You can use those named scopes as filters by declaring

them on your controller and just need to call apply_scopes to an specific resource. 1 class GraduationsController < 2 ApplicationController 3 has_scope :featured, :type => :boolean 4 has_scope :by_degree 5 has_scope :by_period, :using => [:started_at, 6 :ended_at], : 7 type => :hash 8 9 def index 10 @graduations = apply_scopes(Graduation).all 11 end 12 end

/graduations?by_period[started_at]=20100701&by_period[ended_at]=20101013

Page 107: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

has_scope• You can use those named scopes as filters by declaring

them on your controller and just need to call apply_scopes to an specific resource. 1 class GraduationsController < 2 ApplicationController 3 has_scope :featured, :type => :boolean 4 has_scope :by_degree 5 has_scope :by_period, :using => [:started_at, 6 :ended_at], : 7 type => :hash 8 9 def index 10 @graduations = apply_scopes(Graduation).all 11 end 12 end

/graduations?featured=true&by_degree=phd

Page 108: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Tragedy at the admin theme

Find out a good design which have smooth operating and fancy

Page 109: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

turbolinks & pjax• Instead of letting the browser recompile the JavaScript and

CSS between each page change, it keeps the current page instance alive and replaces only the body (or parts of) and the title in the head.

• Same advantages: good user experience, reduce bandwidth and server cost

• In particular with Rails:

• more detail: http://goo.gl/Lx7mHk

# Gemfile gem “turbolinks”

# app/assets/javascripts/application.js //= require tubolinks

$.pjax({url:’authors’, container:’#main’})

if request.headers[‘X-PJAX’] render:layout end

Page 110: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事
Page 111: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

rails-gem-list• A workman must sharpen his tools if he is to do his work

well / ⼯工欲善其事,必先利其器

• We’ve done a gem: rails-gem-list

• You can go through rails-gem-list to know how to construct your project architecture and DB schema. Just like

• acts_as_taggable

• ransack

• …

Page 112: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

rails-gem-list• A workman must sharpen his tools if he is to do his work

well / ⼯工欲善其事,必先利其器

• We’ve done a gem: rails-gem-list

• You can go through rails-gem-list to know how to construct your project architecture and DB schema. Just like

• acts_as_taggable

• ransack

• …

Page 113: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Finally• If you want to do a media website, you can follow edit-flow to

manage your posts.

• If your WordPress website becomes larger and larger, you can rewrite your front-end with Rails.

• Please don’t even think to transfer the whole site from WordPress to Rails.

• After we had spoken many topics, there are still two main parts we didn’t present

• Server Architecture

• Data Migration

Page 114: 2015 rubyconf - 百大媒體網站從 Wordpress 到 Rails 的大小事

Special Thanks

X

@dlackty @ymowov

@baojjeu @st0012 @nanasyu @eugg @chentyphoon @randyhsieh @fufukwang

Contact me: [email protected]