เพิ่มบัญชีผู้ใช้

6

แปลไปแล้ว

ในบทนี้ คุณจะได้

  • รู้วิธีการเพิ่มผู้ใช้งานใน Meteor
  • ใส่การตรวจสอบที่จำเป็นให้ Microscope
  • ใช้แพ็คเกจ account-ui สร้างส่วนติดต่อผู้ใช้
  • ที่ผ่านมาเราได้สร้างแอพต้นแบบ โดยนำข้อมูลโพสต์ตัวอย่างมาแสดงผลออกหน้าเว็บในแบบที่ใช้ได้ดีทีเดียว

    และเรายังรู้ด้วยว่าหน้าจอจะปรับเปลี่ยนเนื้อหาเมื่อข้อมูลเปลี่ยนแปลงได้ยังไง ไม่ว่าจะแก้ไขหรือเพิ่มข้อมูลมันก็ตอบสนองได้ในทันที แต่ติดตรงที่ว่าแอพเรายังไม่สามารถป้อนข้อมูลเข้าไปได้ อันที่จริงยังไม่รองรับผู้ใช้งานด้วยซ้ำ

    ถ้าอย่างนั้น ลองมาดูกันว่าจะแก้ไขเรื่องพวกนี้ได้ยังไง

    บัญชีผู้ใช้: ไม่ยากอย่างที่คิด

    เฟรมเวิร์คบนเว็บส่วนมาก เมื่อเราต้องการเพิ่มบัญชีผู้ใช้งานเข้าไปมักเป็นเรื่องน่าเบื่อที่ต้องเจออยู่บ่อยๆ แน่นอนว่าเราต้องทำกับแทบทุกโปรเจกต์ แต่มัันไม่เคยง่ายอย่างที่ควรจะเป็นเลย ยิ่งกว่านั้นถ้าเราต้องยุ่งกับ OAuth หรือ ระบบตรวจสอบผู้ใช้แบบอื่นๆแล้วละก็ โค้ดที่เสร็จแล้วมักจะดูไม่ได้เลย

    โชคดีที่ Meteor ช่วยเราได้ ด้วยวิธีจัดการแพคเกจที่ทำให้เราใช้โค้ดร่วมกันได้ทั้งบนเซิร์ฟเวอร์ (จาวาสคริปต์) และไคลเอนต์ (จาวาสคริปต์ HTML และ CSS) นั่นก็คือเราแทบจะได้ระบบบัญชีผู้ใช้มาฟรีๆ

    เราอาจเลือกใช้แพ็คเกจบัญชีผู้ใช้ที่มาพร้อมกับ Meteor (ด้วยคำสั่ง meteor add accounts-ui) แต่เนื่องจากเราสร้างแอพด้วย Bootstrap เราก็ควรใช้แพ็คเกจ ian:accounts-ui-bootstrap-3 แทน (ไม่ต้องกังวลไป ที่แตกต่างกันก็แค่สไตล์หน้าเว็บเท่านั้น) โดยให้ป้อนคำสั่งดังนี้ :

    meteor add ian:accounts-ui-bootstrap-3
    meteor add accounts-password
    
    Terminal

    คำสั่งทั้งสองนี้จะสร้างเทมเพลทบัญชีผู้ใช้เพิ่มให้เรา โดยเราสามารถนำมาใส่ในแอพได้ด้วยตัวช่วย {{> loginButtons}} และถ้าคุณต้องการควบคุมตำแหน่งของปุ่มล็อกอินว่าจะให้แสดงที่ด้านไหนก็แค่เพิ่มคุณสมบัติ align เข้าไป (เช่น {{> loginButtons align="right"}})

    เราจะเพิ่มปุ่มนี้เข้าไปที่ส่วนหัวของหน้าแอพ และเนื่องจากส่วนหัวนี้เริ่มจะมีข้อมูลเยอะขึ้น เราก็จะสร้างเทมเพลทส่วนตัวให้มัน (วางไว้ที่ client/templtes/includes/) โดยใส่แท็กและคลาสเพิ่มเติมเข้าไปด้วย ตามที่ Bootstrap แนะนำ เพืิ่อให้ทั้งหมดดูดี :

    <template name="layout">
      <div class="container">
        {{> header}}
        <div id="main">
          {{> yield}}
        </div>
      </div>
    </template>
    
    client/templates/application/layout.html
    <template name="header">
      <nav class="navbar navbar-default" role="navigation">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navigation">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="{{pathFor 'postsList'}}">Microscope</a>
        </div>
        <div class="collapse navbar-collapse" id="navigation">
          <ul class="nav navbar-nav navbar-right">
            {{> loginButtons}}
          </ul>
        </div>
      </nav>
    </template>
    
    client/templates/includes/header.html

    ตอนนี้เมื่อเราเปิดไปที่หน้าแอพ เราจะเห็นปุ่มล็อกอินที่มุมขวาบนของหน้าจอ

    Meteor's built-in accounts UI
    Meteor’s built-in accounts UI

    เราสามารถใช้ปุ่มนี้ สร้างบัญชีผู้ใช้ ล็อกอิน ขอแก้รหัสผ่าน และอื่นๆ ที่แอพง่ายๆจำเป็นต้องมีเพื่อจัดการบัญชีผู้ใช้ได้

    และเพื่อบอกให้ระบบบัญชีผู้ใช้รู้ว่าเราต้องการให้ผู้ใช้งานล็อกอินด้วยชื่อ เราก็แค่เพิ่มบล็อก Accounts.ui ในไฟล์ config.js ที่สร้างขึ้นใหม่ใน client/helpers/ ดังนี้ :

    Accounts.ui.config({
      passwordSignupFields: 'USERNAME_ONLY'
    });
    
    client/helpers/config.js

    คอมมิท 6-1

    Added accounts and added template to the header

    สร้างผู้ใช้คนแรก

    เริ่มสร้างบัญชีผู้ใช้ใหม่กันได้เลย เมื่อทำเรียบร้อยปุ่ม “Sign in” ก็จะเปลี่ยนไปเป็นชื่อผู้ใช้งานของคุณ เพื่อยืนยันว่าบัญชีผู้ใช้ของคุณได้ถูกสร้างขึ้นแล้ว แต่ทว่าข้อมูลบัญชีนี้ถูกเก็บไว้ที่ไหนกันล่ะ

    ตอนที่เราเพิ่มแพ็คเกจ account เข้าไปนั้น Meteor ก็สร้างคอลเลคชั่นใหม่ขึ้นมาหนึ่งตัว โดยสามารถเรียกใช้ได้จาก Meteor.users ซึ่งถ้าเราเปิดคอนโซลของเบราว์เซอร์และพิมพ์คำสั่งต่อไปนี้ :

     Meteor.users.findOne();
    
    Browser console

    คอนโซลก็จะแสดงอ็อบเจกต์ของผู้ใช้ที่คุณสร้างไว้ และถ้าดูตรงข้อมูลก็จะเห็นชื่อผู้ใช้งานของคุณ รวมทั้ง _id ที่มีค่าเฉพาะใช้อ้างถึงคุณได้ นอกจากนี้คุณยังสามารถใช้คำสั่ง Meteor.user() เพื่อเรียกข้อมูลผู้ใช้งานปัจจุบันที่ล็อกอินอยู่ได้ด้วย

    ตอนนี้ให้คุณล็อกเอาท์ และลองสร้างบัญชีผู้ใช้ใหม่อีกรอบด้วยชื่ออื่น ซึ่งถ้าตอนนี้เราใช้คำสั่ง Meteor.user() ก็น่าจะได้ข้อมูลผู้ใช้คนที่สองนี้ออกมา แต่ช้าก่อน ลองรันคำสั่งนี้ดู :

     Meteor.users.find().count();
    1
    
    Browser console

    คอนโซลคืนค่ามาเป็น 1 แต่เดี๋ยวก่อน มันควรจะเป็น 2 นี่ หรือว่ามีใครแอบลบบัญชีแรกออกไปแล้ว ถ้าคุณลองล็อกอินด้วยชื่อบัญชีแรกก็จะเห็นว่ามันยังคงใช้ได้อยู่

    เพื่อให้แน่ใจเราลองมาเช็คจากที่เก็บข้อมูลเลยดีกว่า ก็ที่ฐานข้อมูล Mongo ไง โดยเราจะล็อกอินไปที่ Mongo (ด้วยคำสั่ง meteor mongo ในเทอร์มินอล) แล้วเช็คดูดังนี้ :

    > db.users.count()
    2
    
    Mongo console

    มันมีข้อมูลผู้ใช้อยู่ 2 คนจริงๆ แต่ว่าทำไมเราถึงเห็นแค่คนเดียวจากในเบราว์เซอร์ล่ะ

    ความพิศวงของการส่งข้อมูล !

    ถ้าคุณคิดย้อนกลับไปถึงบทที่ 4 คุณอาจจำได้ว่าการปิด autopublish ก็คือการที่เราห้ามไม่ให้คอลเลคชั่นที่เซิร์ฟเวอร์ส่งข้อมูลทั้งหมดมาให้คอลเลคชั่นในไคลเอนต์ที่เชื่อมต่อกันอยู่โดยอัตโนมัติ ดังนั้นเราถึงต้องสร้างช่องทางการส่งและบอกรับข้อมูลขึ้นมาเอง

    แต่เราก็ยังไม่เคยกำหนดให้มีการส่งข้อมูลบัญชีผู้ใช้ด้วยซ้ำ แล้วเราเห็นข้อมูลพวกนี้ได้ยังไงกัน

    คำตอบก็คือ แพ็คเกจจัดการบัญชีผู้ใช้ ทำการส่งข้อมูลรายละเอียดผู้ใช้งานปัจจุบันมาให้เองโดยอัตโนมัติ (auto-publish) เพราะถ้าไม่ทำอย่างนั้น ผู้ใช้คงไม่มีทางล็อกอินเข้าแอพได้เลย !

    แต่แพ็คเกจจัดการบัญชีผู้ใช้จะส่งเฉพาะค่าของ ผู้ใช้ปัจจุบัน มาให้เท่านั้น ทำให้อธิบายได้ว่าทำไมผู้ใช้งานปัจจุบันถึงไม่เห็นข้อมูลของผู้ใช้คนอื่น

    นั่นก็คือจะมีการส่งข้อมูลเฉพาะของผู้ใช้งานปัจจุบันที่ล็อกอินเข้ามาแล้วเท่านั้น และไม่ส่งอะไรมาเลยถ้าคุณไม่ได้ล็อกอิน

    มากไปกว่านั้น คอลเลคชั่นของข้อมูลผู้ใช้บนเซิร์ฟเวอร์ก็ไม่เหมือนกับที่ไคลเอนต์ด้วย โดย Mongo จะเก็บข้อมูลผู้ใช้ไว้หลายอย่าง ซึ่งเราดูได้จากคำสั่งนี้ในคอนโซล Mongo :

    > db.users.find()
    {
      "_id": "H5kKyxtbkLhmPgtqs",
      "createdAt": ISODate("2015-02-10T08:26:48.196Z"),
      "profile": {},
      "services": {
        "password": {
          "bcrypt": "$2a$10$yGPywo3/53IHsdffdwe766roZviT03YBGltJ0UG"
        },
        "resume": {
          "loginTokens": [{
            "when": ISODate("2015-02-10T08:26:48.203Z"),
            "hashedToken": "npxGH7Rmkuxcv098wzz+qR0/jHl0EAGWr0D9ZpOw="
          }]
        }
      },
      "username": "sacha"
    }
    
    Mongo console

    ส่วนที่เบราว์เซอร์นั้น ข้อมูลผู้ใช้จะเหลือแค่นิดเดียว ดูได้จากคำสั่งที่คล้ายกันดังนี้ :

     Meteor.users.findOne();
    Object {_id: "kYdBd9hr3fWPGPcii", username: "tmeasday"}
    
    Browser console

    ตัวอย่างนี้แสดงให้เราเห็นว่าคอลเลคชั่นที่ไคลเอนต์เป็นเพียง ชุดข้อมูลย่อย ของฐานข้อมูลจริงได้อย่างไร ผู้ใช้ที่ล็อกอินจะเห็นเพียงแค่ชุดข้อมูลที่เพียงพอต่อการใช้งานเท่านั้น (แค่ให้ล็อกอินได้) ซึ่งเราจะได้เรียนรู้รูปแบบการทำงานนี้ในโอกาสต่อไป

    ทั้งหมดนี้ไม่ได้หมายความว่าคุณไม่สามารถใช้ข้อมูลอื่นจากบัญชีผู้ใช้ได้ ถ้าคุณดูที่ หน้าเอกสารของ Meteor ก็จะรู้วิธีการเลือกส่งข้อมูลอื่นๆที่ต้องการจากคอลเลคชั่น Meteor.users มาใช้งานได้