Slide 1

Slide 1 text

ই֜ڥአ Rails ࣁ 21 ॠ ܔຖ܃ḘӤᕚӞӻԾߝ ๫Եᷢ For RubyConf China 2016 2016.09.24

Slide 2

Slide 2 text

๫Եᷢ Ⴎࣉ Ruby ၚۖᕟᕢᘏ ᳯ᷌ᥴ٬ᘏ, ޾Ӟӻ፥ᦻጱՈ ؉ᬦ cywin, jiaoluo, 51goda ᒵ, ፓڹ೮ᖅڠӱࣁ github: ruby-china: 80% @windy @lyfi2003

Slide 3

Slide 3 text

؉ӞӻԾߝಅᵱጱᚆێ Ծߝ௏ᖌ ದ๞ᚆێ ᦡᦇᚆێ ᬩ០ᚆێ

Slide 4

Slide 4 text

ྯӞӻ Rails ૡᑕ૵᮷ଫᧆํӞ ӻᛔ૩ᳩ๗ᖌಷጱᶱፓ

Slide 5

Slide 5 text

ٖ਻

Slide 6

Slide 6 text

ᒫᵭྍ Ծߝᦎᦞ

Slide 7

Slide 7 text

ك܈ԫ܈فݗ: https://80post.com

Slide 8

Slide 8 text

ಚᎱ֛ḵ

Slide 9

Slide 9 text

֢ᘏᒒ Ӟӻ PC ᒒଫአ ٟ՞ᩇ෈ᒍଚਧհ ಋ๢ಚӞಚړՁ ஙמ๐ۓݩັᧃ

Slide 10

Slide 10 text

᧛ᘏᒒ ஙמଫአ ஙמٖඪ՞ଚᴅ᧛ ᦧհ, ݊PCᒒݶྍᴅ᧛ ஙמ๐ۓݩັᧃ

Slide 11

Slide 11 text

ଘݣᒒ PC ᒒ හഝᕹᦇ ᔮᕹᓕቘ

Slide 12

Slide 12 text

ᒫӞྍ لݪဳٙ ऒݷ॓ໜ ஙמلռݩ

Slide 13

Slide 13 text

ᕹᓉොဩ਍ ض؉๋ݢᚆᴥल֕ݢզଚᤈጱԪఘ

Slide 14

Slide 14 text

ض୏ত? ୮ᆐฎ "ஙמᦊᦤ" ...

Slide 15

Slide 15 text

ஙמ๐ۓݩ ஙמᦈᴅݩ ஙמ୏නଘݣ ஙמࠟಁݩ ஙמմӱݩ ஙמੜᑕଧݩ ತӧݶ ๋ᕣ, ౯ժԻԧ 1200 Ո࿆૰!!!

Slide 16

Slide 16 text

ᑕଧާ ੜᑕଧާ ๋ᕣ, ᬯӻӮኴਖ਼ړԅ

Slide 17

Slide 17 text

لݪဳٙ ᭌӻ ྲই 80percent vs 37signals( ضਧӻੜፓຽ ) ဳٙࣈஉ᯿ᥝ( ྲইႮࣉڹၹ ) വគತӻᶌᨏጱդېلݪ অݷਁ

Slide 18

Slide 18 text

ऒݷ॓ໜ ੱᰁአ .com ᘒӧฎ .cn ٵ॓অ 20 ॠጱ॓ໜ෸ᳵ ኪᦾ݊෸ള

Slide 19

Slide 19 text

ᒫԫྍ ದ๞ᭌࣳ

Slide 20

Slide 20 text

Rails5 قਹ໲

Slide 21

Slide 21 text

Ruby on Rails 5 turbolinks5 actioncable bootstrap 3 font-awesome figaro postgres slim high_voltage carriewave & upyun sidekiq kaminari mina

Slide 22

Slide 22 text

VS Vue ୏ݎ᭛ଶள( ᫷ڹᒒଫአ ) አಁ֛ḵঅ( turbolinks5 ඪ ൔ ) ӧտଃ๶ឭݷጱᳯ᷌( SEO, Ḓᶭے᫹᭛ଶᒵ ) ݸᒒኞா෫ᥴᙑ VS React React قਹ໲਍ԟ౮๜ṛ ᭛ଶள, ֛ḵঅ( ᫷ڹᒒଫ አ, turbolinks5ඪൔ ) ݸᒒኞாսᐹӬ౮ᆧ ᫷ڹᒒଫአ turbolinks + Rails5 ᬱսԭڹᒒ໛ຝ

Slide 23

Slide 23 text

ᒫӣྍ( ದ๞ᓤ ) Ծߝᬽդ୏ݎ

Slide 24

Slide 24 text

3.1 ᦡᦇහഝᕮ຅

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

Ⴔศጱ޸ݷฎىᲫ ىᘶىᔮጱ޸ݷԞஉ᯿ᥝ מ௳ӧᥝٞ֟ class User # other codes has_many :reader_orders, class_name: 'Order', foreign_key: 'reader_id' has_many :writer_posts, class_name: 'Post', foreign_key: 'writer_id' end

Slide 27

Slide 27 text

3.2 Turbolinks5

Slide 28

Slide 28 text

አಁ֛ḵঅ( ݢྲ SPA ଫአ ) ୏ݎපሲṛ ਍ԟ౮๜֗ սᅩ

Slide 29

Slide 29 text

ဳ఺ᅩ ඙֢ӧ଍ᒵ෸ىᳮ cache ࣁஙמ6.1զӥᇇ๜ىᳮ᧣አ jssdk ጱᶭᶎ // page1.html - content_for :head do meta name="turbolinks-cache-control" content="no-cache" // layouts/application.html.slim = csrf_meta_tags = content_for?(:head) ? yield(:head) : '' // ----------------- // app/views/wechat/writer/readers/index.html.slim = link_to order.post.short_title, reader_post_path(order.post), data: { turbolinks: false }

Slide 30

Slide 30 text

Turbolinks ᮎԶԪ ๅग़ turbolinks5 ጱᳯ᷌? ᧗ັᴅ:

Slide 31

Slide 31 text

3.3 wxpay Ө ActionCable

Slide 32

Slide 32 text

ᵭ୊᬴ጱඪ՞֛ḵ

Slide 33

Slide 33 text

wxpay gem & sjr function jsApiCall(){ showSpin(<%= @order.id %>); WeixinJSBridge.invoke( 'getBrandWCPayRequest', <%= raw @js_pay_hash.to_json %>, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok") { }else if( res.err_msg == "get_brand_wcpay_request:cancel" ){ hideSpin(); $.post("<%= cancel_reader_orders_path(order_id: @order.id) %>"); } } ); } function callpay(){ if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); } }else{ jsApiCall(); } } callpay();

Slide 34

Slide 34 text

wxpay & actioncable # order action cable( order_channel.rb ) class OrderChannel < ApplicationCable::Channel def subscribed stream_from "order_for_#{params[:order_id]}" end end # order.rb class Order def send_cable_notify ActionCable.server.broadcast "order_for_#{self.id}", {} ActionCable.server.broadcast "user_post_for_user_#{self.reader_id}_and_post_#{self.post_id}", { end end // javascripts/pay_helper.js function showSpin(order_id){ window.App.order_channel = window.App.cable.subscriptions. create( {channel: 'OrderChannel', order_id: order_id}, { received: function(){ $('#spin').spin(false); Turbolinks.visit(); } }); $('#spin').css('z-index', 1).spin().css('background-color', 'rgba(0,0,0,0.2)'); }; function hideSpin(){ $('#spin').css('z-index', -1).spin(false).css('background-color', 'transparent'); }

Slide 35

Slide 35 text

ᵭ୊᬴֛ḵඪ՞᭗Ꭳ ᭦ᬋፗᥡ SJR ӨڹᒒJSᜉঅᯈݳ

Slide 36

Slide 36 text

3.4 JS ޾ CSS ೆړ

Slide 37

Slide 37 text

Layout ೆړ wechat layouts writer layouts admin layouts

Slide 38

Slide 38 text

JS ೆړ application.js wechat_base.js writer_base.js admin_base.js

Slide 39

Slide 39 text

CSS ೆړ application.css wechat_base.css writer_base.css

Slide 40

Slide 40 text

໐ஞྍṈ ᑏᴻ require_tree . ԅྯӞᐿ᥯ᜋڠୌӞӻ layout ړڦٵ॓ਙժጱ js Ө css, ଚوአᕮ຅ ࣁ initializers/assets.rb Ⴒے੒ଫጱ js Ө css

Slide 41

Slide 41 text

ᕮຎ 300KB -> 80KB, ے᫹᭛ଶ൉܋ 300% ᯈݳ cdn አಁᑏۖᒒࣁ 700ms ૢݦ಑୏ଫአ

Slide 42

Slide 42 text

3.5 ActionCable ๅग़ ଫአ

Slide 43

Slide 43 text

አಁࣁኪᚏᒒ಑୏෈ᒍ, ಚᎱᨻԣ, ኪᚏᒒܨ ෸ݶྍᴅ᧛ ᘍᡤጭ୯Ө๚ጭ୯ఘ٭ ௏ᘍӞӻᵱ࿢

Slide 44

Slide 44 text

ᥴ٬ොໜ Token for user&post Redis Channel Name: user_post_for_user_id_post_id

Slide 45

Slide 45 text

Channel # user_post_channel.rb class UserPostChannel < ApplicationCable::Channel def subscribed stream_from "user_post_for_user_#{params[:user_id]}_and_post_#{params[:post_id]}" end def unsubscribed # Any cleanup needed when channel is unsubscribed end end

Slide 46

Slide 46 text

Notification # order.rb def send_cable_notify ActionCable.server.broadcast "order_for_#{self.id}", {} ActionCable.server.broadcast "user_post_for_user_#{self.reader_id}_and_post_#{self.post_id}" , {} end

Slide 47

Slide 47 text

# post_token.rb class PostToken redis = Redis.new @hash = Redis::Namespace.new(ENV['TOKEN_NAMESPACE'], :redis => redis) @order_token_map = Redis::Namespace.new(ENV['TOKEN_NAMESPACE'] + '_order_token_map', :redis => re @expire_time = 60 * 60 * 24 * 7 * 2 class <

Slide 48

Slide 48 text

ᒫࢥྍ ၥᦶӨݎ૲

Slide 49

Slide 49 text

ၥᦶள᩸๶ Test Mode wxpay sidekiq: async -> sync

Slide 50

Slide 50 text

Test Mode # routes.rb Rails.application.routes.draw do if ENV['USER_TEST_DEBUG'].present? get '/test' => 'visitors#test' get '/test_for_new_user' => 'visitors#test_for_new_user' get '/test_for/:id' => 'visitors#test_for' end end # OrdersController#pay if ENV['USER_TEST_DEBUG'].present? if @order.may_pay? @order.pay! order_token_for_order_id @order.send_cable_notify end render js: 'alert("ၥᦶཛྷୗඪ՞౮ۑ");Turbolinks.visit();' return end

Slide 51

Slide 51 text

Test Mode( 2 ) # sidekiq worker if ENV['USER_TEST_DEBUG'].present? ServerNotificationWorker.new.perform(title, text) else ServerNotificationWorker.perform_async(title, text) end ᛔۖڠୌӨጭ୯አಁ ੱݢᚆݶྍ඙֢ၥᦶ ຄय़ᜓ፜ၥᦶ౮๜

Slide 52

Slide 52 text

ݎ૲ԯᒒ۸ ASSETS CDN Image CDN Virtual Host

Slide 53

Slide 53 text

CDN # config/environments/production.rb config.action_controller.asset_host = 'https://p8020cdn.b0.xxyun.com' # app/uploaders/image_uploader.rb class ImageUploader < CarrierWave::Uploader::Base storage :xxyun end

Slide 54

Slide 54 text

ᖌಷᛔ૩ጱ᳒؟౲ཛྷ຃ ຤ԯཛྷ຃ ݎ૲ӞᲫ۸ $ mina deploy

Slide 55

Slide 55 text

හഝݢᥤ۸ Charts Data Collection Server Notification

Slide 56

Slide 56 text

Charts # chart gem "chartkick" gem 'groupdate' gem 'linux_fortune'

Slide 57

Slide 57 text

ෛीአಁහ ෛी෈ᒍහ ၨᥦᰁ / ᦈܔ / ݐၾᦈܔ / ؎؎፡ ྯޮ / ྯॠ ᬩ០හഝᥡၥ

Slide 58

Slide 58 text

๋ݸӞྍ: ᬩ០ V2EX RubyChina 36kr ᆽ᝜ .... ....

Slide 59

Slide 59 text

क़ࢱץᅫ UI ᦡᦇӨਭᗦᚆێ Ծߝᦡᦇᚆێ ᬩ០ᚆێ لݪᬩ០ ... ...

Slide 60

Slide 60 text

୏ݎᛗӤᕚᬩ០ Ր 21 ॠ 05.16 ~ 06.06

Slide 61

Slide 61 text

୮ڹහഝ 2800+ አಁ 150+ ෈ᒍ 3000+ ᲀࠓ᷐

Slide 62

Slide 62 text

ࣁ Rails5 ᫥᭲Ӥᬩ០֦ጱԾߝ

Slide 63

Slide 63 text

ኞԾێ௛ᕮ ๋֯ਫ᪢ॺᤰ ᓌ၄ṛපጱ୏ݎቘஷ ኞா୩य़

Slide 64

Slide 64 text

Ծڊጱپӻ᫪ৼ - ள᭛ଫአ rails5 ጱཛྷ຃ - ӞᤈդᎱ೏ᕷ෯ၨᥦ࢏ ( Native APP ཛྷ຃) Rails Template BrowserWarrior Mobx with ReactNative

Slide 65

Slide 65 text

80 ਍ᴺ Ӟ੒Ӟ੕૵ګ ᕚӤර਍ 3 ӻ์ http://www.80academy.com AD

Slide 66

Slide 66 text

ጯړԏك܈ Ⴎࣉ૱ ᗑᕶದ๞ํᴴلݪ ೗ՈӾ ݶ෸൉׀: ڠӱԾߝ MVP ୏ݎ RubyConf ᩩۗࠟ, ᩒාᤢํᧇᕡՕᕨ

Slide 67

Slide 67 text

QA & Thx