江湖險惡,我從來都不輕易留下我的姓名。

憑你的智慧,我唬得了你嗎?

Sails練習之二

| Comments

本篇是接著Irl nathan的這篇

Building a Sails Application: Ep3[UPDATED] - A user model/controller, signup page, sails blueprints

底下為練習內容

MVC架構

Sails有支援MVC架構, 所以若你有想要完成一個概念性的物件, 這個物件有相對的屬性和行為,Sails會將這個物件的屬性放在Modules, 而行為就放在Controller

使用下列的語法來讓Sails自動創建Controller以及Module

1
2
E:\sails_app\activeityOverload>sails generate api user
info: Created a new api!

PS: 舊版的只要輸入sails generate user 就可以了

這樣Sails會在

api\controllers 產生 UserController.js

api\models 產生 User.js

其中,

controllers放的是action的邏輯

modules裡面放的是attributes的設定

OK, 接著我們來設計User的屬性, 修改 User.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module.exports = {

  attributes: {
    name:{
        type: 'string',
        required: true
    },

    title:{
        type: 'string'
    },

    email: {
      type: 'email',
      required: true,
      unique: true
    },

    encryptedPassword:{
        type: 'string'
    }
  }
};

要注意上面的email寫法, sails 0.10以後, type要改成'email'

然後原本的email: true要拿掉

參考這裡

編輯完成之後, 存檔, 執行 sails lift

若是第一次新增api, sails應該會跳出底下的訊息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
E:\sails_app\activeityOverload>sails lift

info: Starting app...

-----------------------------------------------------------------

 Excuse my interruption, but it looks like this app
 does not have a project-wide "migrate" setting configured yet.
 (perhaps this is the first time you're lifting it with models?)

 In short, this setting controls whether/how Sails will attempt to automatically
 rebuild the tables/collections/sets/etc. in your database schema.
 You can read more about the "migrate" setting here:
 http://sailsjs.org/#/documentation/concepts/ORM/model-settings.html?q=migrate

 In a production environment (NODE_ENV==="production") Sails always uses
 migrate:"safe" to protect inadvertent deletion of your data.
 However during development, you have a few other options for convenience:

 1. safe  - never auto-migrate my database(s). I will do it myself (by hand)
 2. alter - auto-migrate, but attempt to keep my existing data (experimental)
 3. drop  - wipe/drop ALL my data and rebuild models every time I lift Sails

What would you like Sails to do?

info: To skip this prompt in the future, set `sails.config.models.migrate`.
info: (conventionally, this is done in `config/models.js`)

warn: ** DO NOT CHOOSE "2" or "3" IF YOU ARE WORKING WITH PRODUCTION DATA **

prompt: ?:  error: Error: The hook `orm` is taking too long to load.
Make sure it is triggering its `initialize()` callback, or else set `sails.config.orm._hookTimeout to a higher value (currently 20000)
    at tooLong [as _onTimeout] (C:\Users\KennyTu\AppData\Roaming\npm\node_modules\sails\lib\app\private\loadHooks.js:92:21)
    at Timer.listOnTimeout (timers.js:89:15)

既然上面有提示到這個網頁, 我們就去看一下

大意就是說, sails他會做一些策略, 來和我們的資料庫互動, migrate(中文有遷移, 移居的意思), 有三種策略, 分別是safe, alter以及drop, 詳細我就不多說了, 去看網頁寫的很清楚

OK, 接下來我們要做的動作是去修改config/models.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module.exports.models = {

  /***************************************************************************
  *                                                                          *
  * Your app's default connection. i.e. the name of one of your app's        *
  * connections (see `config/connections.js`)                                *
  *                                                                          *
  ***************************************************************************/
  // connection: 'localDiskDb',

  /***************************************************************************
  *                                                                          *
  * How and whether Sails will attempt to automatically rebuild the          *
  * tables/collections/etc. in your schema.                                  *
  *                                                                          *
  * See http://sailsjs.org/#!/documentation/concepts/ORM/model-settings.html  *
  *                                                                          *
  ***************************************************************************/
   migrate: 'safe'

};

把migrate改成safe, 再重新執行sails lift

基本上應該就沒問題可以正常執行了

接下來開啟瀏覽器, 輸入底下網址..

作者在輸入到一半的時候,故意只輸入部分, 來讓我們看一下出錯的效果

http://localhost:1337/user/create?name=kenny

伺服器回應的結果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
  "error": "E_VALIDATION",
  "status": 400,
  "summary": "1 attribute is invalid",
  "model": "User",
  "invalidAttributes": {
    "email": [
      {
        "rule": "email",
        "message": "`undefined` should be a email (instead of \"null\", which is a object)"
      },
      {
        "rule": "required",
        "message": "\"required\" validation rule failed for input: null"
      }
    ]
  }
}

大意就是說, email需要輸入

我們再改一個正常的

在瀏覽器輸入URL如下

http://localhost:1337/user/create?name=kennyg&email=i@a.com

注意email不能有用過的, 因為我們將email的其中一個unique的屬性設定為true

若沒有意外, 應該出現如下視窗

1
2
3
4
5
6
7
{
  "name": "kennyg",
  "email": "i@a.com",
  "createdAt": "2015-11-17T07:19:54.897Z",
  "updatedAt": "2015-11-17T07:19:54.897Z",
  "id": 2
}

大功告成啦!

注意一點, 我們現在還沒有對UserController.js寫任何邏輯, 以上的行為都是sails系統預設的 :)

預設行為都放在blueprints.js下

接下來, 我們要開始弄View的東西, 之前Sails幫我們自動生成Module以及Controller,

我們手動在views新增一個資料夾user,然後在user資料夾新增一個檔案名為new.ejs, 新增內容如下

1
<h1> User signup Form </h1>

回到UserController.js, 在api\controllers底下

我們新增以下的code

1
2
3
4
5
module.exports = {
    'new': function(req, res){
        res.view();
    }
};

重新啟動sails, 回到瀏覽器輸入localhost:1337, 按下Sing Up now, 視窗就會跳到new.ejs的page去

還記得嗎? 我們在static底下的index.ejs, button的href是指到/user/new這個action, 所以就會跳到new這邊來了

一般來說, sails會自動幫我們對應action以及底下的檔案, 若要關掉它, 就要去設定

現在我們修改blueprints.js, 在config底下

找到rest, 把他設定成false. 記得要把註解拿掉

參照以下設定

rest: false,
shortcuts: false,
actions: false,

設定好, 存檔, 重新啟動sails

這時候進入首頁, 按下Sing up now, 我們會被導入404 pages

接著我們就開始手工打造我們的mapping

回到routes.js, 加入底下的code

routes.js 片段
1
2
3
4
5
6
'/': {
    view: 'static/index'
      },
      '/user/new': {
  view: 'user/new'
      }

從新啟動sails, 再次執行sing up now, 就可以導向到我們的頁面了

另一種routes.js風格的寫法, 如下

1
2
3
4
   'user/new': {
      controller: "UserController",
      action:"new"
      }

這樣的寫法我在新版的sails上面都沒有辦法get到頁面, 不知道是不是要明確指定view才行

另外, 有關routes的其他寫法, 請參考Custom RoutesController / action target syntax 章節

ok, 我們先繼續, 等之後有靈感在回來試試看

現在先將剛剛在routes.js加入的'user/new'這一些敘述都刪掉, 存檔

回到blueprints.js, 將action改成true

然後修改new.ejs, 如底下的程式碼

new.ejs
1
2
3
4
5
6
7
8
9
10
11
12
<form action="/user/create" method="POST" class="form-signin">
  <h2 > Create an account</h2>
  <input type="text" class="form-control" placeholder="your name" name="name">
  <input type="text" class="form-control" placeholder="your title" name="title">
  <input type="text" class="form-control" placeholder="email address" name="email">
  <input type="password" class="form-control" placeholder="password" name="password">
  <input type="password" class="form-control" placeholder="password confirmation" name="comfirmation">

  <input type="submit" class="btn btn-lg btn-primary btn-block" value="Create Account"/>
  <input type="hidden" name="_csrf" value="<%= _csrf %>"/>

</form>

由於new.ejs有用到一些css, 作者也對custom.less做了一些修改

程式碼如下

custom.less
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@white: #FFFFFF;
@green: #9EC03B;
@orange: #F48744;
@blue: #189ECA;
@gray: #777574;
@lightGrey: #AAAAAA;
@darkBlue: #106E8D;
@darkGray: #4A4A4A; // paragraphs
@red: #D16565; // error

body {
  padding-top: 60px;
  padding-bottom: 40px;
}

.jumbotron {
  text-align: center;
}

.jumbotron h2 {
  font-size: 1.5em;
  letter-spacing: -1px;
  margin-bottom: 30px;
  text-align: center;
  font-weight: normal;
  color: gray;
}

.container .gray{
  color: gray
}

.container{
  .footer{
    width: 25%;
  }
}

.form-signin {
  max-width: 30%;
  padding: 19px 29px 29px;
  margin: 0 auto 20px;
  margin-top: 20px;
  background-color: @lightGrey;
  border: 1px solid @green;
  -webkit-border-radius: 15px;
  -moz-border-radius: 15px;
  border-radius: 15px;

    h2{
      text-align: center;
      margin-top: 0px;
    }
}

.form-signin input[type="text"],
.form-signin input[type="password"]{
  font-size: 16px;
  height: auto;
  margin-bottom: 15px;
  padding: 7px 9px;
}

OK, 回到瀏覽器, 在reflash一次, 應該會出現像樣的登入畫面了

以上就是這一堂課的練習

Comments