Upgrade to Pro — share decks privately, control downloads, hide ads and more …

如何利用 Rails 在 21 天单枪匹马上线一个产品

yafei lee
September 26, 2016

如何利用 Rails 在 21 天单枪匹马上线一个产品

结合八十二十产品的开发,讲如何从零开发出理想产品的演进过程。
此话题涵盖了 Turborlinks、微信支付、ActionCable 等技术以及八十二十的实践经验。

yafei lee

September 26, 2016
Tweet

Other Decks in Technology

Transcript

  1. ๫Եᷢ Ⴎࣉ Ruby ၚۖᕟᕢᘏ ᳯ᷌ᥴ٬ᘏ, ޾Ӟӻ፥ᦻጱՈ ؉ᬦ cywin, jiaoluo, 51goda

    ᒵ, ፓڹ೮ᖅڠӱࣁ github: ruby-china: 80% @windy @lyfi2003
  2. Ruby on Rails 5 turbolinks5 actioncable bootstrap 3 font-awesome figaro

    postgres slim high_voltage carriewave & upyun sidekiq kaminari mina
  3. VS Vue ୏ݎ᭛ଶள( ᫷ڹᒒଫአ ) አಁ֛ḵঅ( turbolinks5 ඪ ൔ )

    ӧտଃ๶ឭݷጱᳯ᷌( SEO, Ḓᶭے᫹᭛ଶᒵ ) ݸᒒኞா෫ᥴᙑ VS React React قਹ໲਍ԟ౮๜ṛ ᭛ଶள, ֛ḵঅ( ᫷ڹᒒଫ አ, turbolinks5ඪൔ ) ݸᒒኞாսᐹӬ౮ᆧ ᫷ڹᒒଫአ turbolinks + Rails5 ᬱսԭڹᒒ໛ຝ
  4. Ⴔศጱ޸ݷฎىᲫ ىᘶىᔮጱ޸ݷԞஉ᯿ᥝ מ௳ӧᥝٞ֟ 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
  5. ဳ఺ᅩ ඙֢ӧ଍ᒵ෸ىᳮ 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 }
  6. 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();
  7. 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'); }
  8. ໐ஞྍṈ ᑏᴻ require_tree . ԅྯӞᐿ᥯ᜋڠୌӞӻ layout ړڦٵ॓ਙժጱ js Ө css,

    ଚوአᕮ຅ ࣁ initializers/assets.rb Ⴒے੒ଫጱ js Ө css
  9. 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
  10. # 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 <<self def generate SecureRandom.uuid.tr('-', '') end def bind_order(order_id, token) @order_token_map.set(order_id, token) @order_token_map.expire(order_id, @expire_time) end def is_bind_order?(order_id) @order_token_map.get(order_id).present? end def order(order_id) token = @order_token_map.get(order_id) if token @hash.set(token, true) @hash.expire(token, @expire_time) # notify ActionCable.server.broadcast "order_token_for_#{token}", {} end end end end Post Token
  11. 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
  12. Test Mode( 2 ) # sidekiq worker if ENV['USER_TEST_DEBUG'].present? ServerNotificationWorker.new.perform(title,

    text) else ServerNotificationWorker.perform_async(title, text) end ᛔۖڠୌӨጭ୯አಁ ੱݢᚆݶྍ඙֢ၥᦶ ຄय़ᜓ፜ၥᦶ౮๜
  13. Ծڊጱپӻ᫪ৼ - ள᭛ଫአ rails5 ጱཛྷ຃ - ӞᤈդᎱ೏ᕷ෯ၨᥦ࢏ ( Native APP

    ཛྷ຃) Rails Template BrowserWarrior Mobx with ReactNative