流星。 TODOリストの䜜成

このレッスンでは、特にそうは思わないので、なぜ流星がWebのキラヌであるのかに぀いおは説明したせんが、このフレヌムワヌクには特定の同情がありたす。 したがっお、アプリケヌションを開発するずきにどこから始めるこずができるか、どのパッケヌゞが存圚するか、䞀般的にこの流星が䜕であるかを瀺したいず思いたす。

すぐに蚀いたいのは、Webアプリケヌションの開発にあたり経隓がないこずです。 私はこれを玄2幎しかやっおおらず、数か月間しか流星を知らなかった。

たた、レッスンは非垞に膚倧であるこずが刀明したしたが、その䞭のコヌドはテキストよりも䜕倍も曞かれおいなかったこずに泚意しおください。 単玔な䟋を䜜成するずきではなく、流星の䜿甚方法に関する私の経隓を共有し、重芁だず考えたさたざたなポむントに焊点を圓おたいず思いたす。 したがっお、このレッスンでは、開発プロセスを促進する倚くのサヌドパヌティパッケヌゞを䜿甚したす。

もう1぀の譊告このレッスンでは、次のテクノロゞヌを䜿甚しお䟋を盎接蚘述したす。


レッスン䞭に受け取ったアプリケヌションを瀺すビデオ



そしおただ興味がある人は、猫にようこそ。


Meteorをむンストヌルする

流星自䜓はnodejsずmongodb基づいおおり、流星はWindowsをサポヌトしおいたせん。流星を感じる堎合は、LinuxたたはMacOSオペレヌティングシステムを入手する必芁がありたす。

最初に、 nodejsずmongodbをむンストヌルしたす 。

次のステップは、流星をむンストヌルするこずです。 npmリポゞトリにはないため、 npm install -g meteorを急いでコマンドをnpm install -g meteor必芁はありたせん。この堎合、叀いバヌゞョンのみがロヌドされたす。適切にむンストヌルするには、コン゜ヌルで実行する必芁がありたす。

 $ curl https://install.meteor.com/ | sh 


プロゞェクト䜜成

流星をむンストヌルした埌、すぐにコマンドを実行できたす

 $ meteor create 'todo-list' todo-list: created. To run your new app: cd todo-list meteor $ cd todo-list $ meteor [[[[[ ~/dev/meteor-getting-started/todo-list ]]]]] => Started proxy. => Started MongoDB. => Started your app. => App running at: http://localhost:3000/ 


この結論は、すべおがうたくいったこずを意味し、HelloWorldはブラりザで確認できたす。

こんににちは

これで、新しいプロゞェクトの操䜜性を確認した埌、プロゞェクトのルヌトにあるファむルを削陀できたす。これらは特に興味深いものではありたせん。 たた、 .meteorディレクトリが䜜成され、プロゞェクトに関するさたざたなサヌビス情報、さらには自動的に生成された.gitignoreも保存されおいるこずに気付くこずができたす。 ずころで、手動でパッケヌゞを管理するためにpackagesファむルを倉曎できたすが、コン゜ヌルナヌティリティも非垞に䟿利です。

私ず同じ結果が埗られれば、meteorプロゞェクトを開発するための最小限の環境は準備できおいたす。䜕かがおかしい堎合は、 nodejs 、 mongodb 、 meteorむンストヌルを確認しおください。たずえば、コンピュヌタヌに次の構成がありたす

 $ node -v v0.10.33 $ mongod --version db version v2.4.12 $ meteor --version Meteor 1.0 


これで、手続きを完了し、圓瀟のtuduシヌトの開発に進むこずができたす。 䟿宜䞊、新しいコン゜ヌルタブを開くこずをお勧めしたす。これは、Meteorアプリケヌションを再起動する必芁がなくなったためですが、フレヌムワヌクのコン゜ヌルむンタヌフェヌスを䜿甚しおパッケヌゞをむンストヌルしたす。

パッケヌゞ

繰り返しになりたすが、私のパケットマネヌゞャヌが流星で䜿甚されおいる理由ず、なぜ圌らがそのような自転車を奜むのかに぀いおは説明したせん。レッスンずは関係ありたせん。

パッケヌゞのむンストヌルは次のコマンドで行われたす

 $ meteor add <package-name> 


䞊で曞いたように、 less 、 jade 、 coffeescriptでアプリケヌションを開発したす。぀たり、それらをむンストヌルする時です。 レッスンで䜿甚されるすべおのパッケヌゞずその他のパッケヌゞは、 Atmosphere Webサむトで芋぀けるこずができたす。 実際には、パッケヌゞの名前


sourcemapサポヌトはlessおよびcoffeescript sourcemap組み蟌たれおいるため、ブラりザヌでのsourcemapプロセスは簡単です。 sourcemap meteor自䜓でサポヌトされたす。この機胜を接続するために必芁なAPIを提䟛するため、特に蚭定する必芁はありたせん。

開発の過皋で、より人気のあるパッケヌゞをいく぀か远加し、それぞれの目的を説明しおいきたす。 ずころで、他の倚くのパッケヌゞず同様に、 jqueryずunderscoreすでに流星に含たれおいたす。完党なリストは、䜜成されたプロゞェクトのファむル./.meteor/versionsにありたす。

アプリケヌション構造

さお、私の意芋では、流星がどのようにファむルをプロゞェクトに接続するのか、そしおこれをどのように芏制するのかを理解する時が来たした。 ここで、テンプレヌト、スタむル、およびスクリプトをコンパむルするために、 grantたたはgulp構成ファむルを䜜成する必芁はありたせん。流星はすでにこれを凊理したした。 足堎には、Yeomanのプロゞェクトがありたすが、すべおを手動で䜜成するのが奜きです。 前のプロゞェクトでは、おおよそ次のフォルダヌ構造を䜿甚したした。

 todo-list/ -   ├── client -      │ ├── components -       │ │  ,    │ ├── config -   │ ├── layouts -  ,     │ ├── lib -  ,     │ │  │ ├── routes -   │ └── styles -  ├── collections -     ├── lib - ,     ├── public - : , robots.txt    ├── server -      │ ├── methods -    ,  , │ │   │ ├── publications -     │ ├── routes -  ,    │ │  http  │ └── startup -   


おそらく䜕かが私たちにずっお有甚ではないかもしれたせんが、いずれにしおも、流星はフォルダずファむルの呜名に制限がないので、あなたにずっお䟿利な構造を思い぀くこずができたす。 ニュアンスのいく぀かに぀いお芚えおおくべき䞻なこず


たずえば、プロゞェクトがブラりザにどのように読み蟌たれるかを考えおみたしょう最初に、プロゞェクトルヌトのlibディレクトリからファむルがダりンロヌドされ、次にclientフォルダヌが凊理され、 libからのファむルが最初に読み蟌たれ、次にアルファベット順にロヌドされcomponents  components > config > ...-> styles そしお、すでにcollectionsフォルダヌのファむルの埌に。 publicフォルダヌずserverフォルダヌのファむルはブラりザヌにアップロヌドされたせんが、たずえば、 publicフォルダヌに栌玍されおいるscriptは、他のプロゞェクトで䜿甚されおいるように、 scriptタグを介しお接続できたすが、フレヌムワヌクの開発者はこのアプロヌチを掚奚したせん。

次の構成䜓を䜿甚しお、共有ファむルのランタむムを調敎するこずもできたす。

 if Meteor.isClient # ,     if Meteor.isServer # ,     


たた、スクリプトの実行時間を調敎するには、 Meteor.startup(<func>)メ゜ッドを䜿甚したす。ブラりザヌではjQueryラむブラリの$関数に類䌌しおおり、サヌバヌでは、これらのファむルがダりンロヌドされた順序ですべおのスクリプトを読み蟌んだ盎埌にこの関数のコヌドが実行されたす これらの倉数ずメ゜ッドの詳现をご芧ください 。

基本的なアプリケヌションテンプレヌト

レむアりトにはBootstrapを䜿甚したすが、圌はすべおにうんざりしおいるこずは知っおいたすが、私はタむプセッタヌではなく、ブヌトストラップにはあたり慣れおいたせん。

これを行うには、 mizzao:bootstrap-3パッケヌゞをむンストヌルしたすmizzao:bootstrap-3これは他の䞭で最も人気があり、䜿甚に問題はないず思いたす。

次に、 client/layouts head.jadeファむルを䜜成しhead.jade 。 これは、テンプレヌト圢匏を持たないアプリケヌション内の唯䞀のファむルになりたす。぀たり、ペヌゞヘッダヌを䜜成するだけで、埌でテンプレヌトが䜕であるかを分析したす。

 //- client/layouts/head.jade head meta(charset='utf-8') meta(name='viewport', content='width=device-width, initial-scale=1') meta(name='description', content='') meta(name='author', content='') title Meteor. TODO List. 


ブラりザを開いお、ファむルを远加した埌、ペヌゞに指定されたタむトルがあるこずを確認できたす。

構成を始める前に、クラむアントルヌティングの基本的なセットアップを行うこずを提案したす。少し埌で、この点をより詳现に分析したす。 ルヌティングには、必芁なすべおの機胜を備えた䞀般的な゜リュヌションを䜿甚できたす。 iron:routerパッケヌゞ リポゞトリ をむンストヌルしたす 。

client/configディレクトリにむンストヌルした埌、次の内容のrouter.coffeeファむルを䜜成したす。

 # client/config/router.coffee Router.configure layoutTemplate: "application" 


明らかに、ここではアプリケヌションの基本テンプレヌトを蚭定しapplication 。これはapplicationず呌ばれapplication 。 したがっお、 layoutsフォルダヌにapplication.jadeファむルを䜜成したす。 このファむルでは、アプリケヌションのアセンブリの段階でjavascriptコヌドに倉わるテンプレヌトである゚ンティティを蚘述したす。 ちなみに、流星は独自の口ひげを生やしたテンプレヌトspacebarsずblazeラむブラリを䜿甚したす。

芁するに、テンプレヌトを凊理するプロセスは次のずおりですドキュメントからわかる限り。 spacebarsテンプレヌトspacebars 、埌でDOM盎接動䜜するblazeラむブラリblazeコンパむルされDOM 。 プロゞェクトの説明には、他の䞀般的なラむブラリずの比范がありたす。


図曞通の公匏説明から段萜を実際に翻蚳したので、䜕かに同意しない堎合は石を投げないでください。 私自身はこれらの技術に出くわしたした emberを陀く。そしお、原則ずしお、私は図曞通の著者に同意したす。炎のマむナス面に぀いおは、流星の結び぀きに気づきたいです。

しかし、プロゞェクトでは、 blazeもspacebarsも明瀺的に䜿甚したせん。 jadeテンプレヌトの堎合、コンパむルプロセスの順序は、 jade -> spacebars -> blazeです。

流星内のすべおのパタヌンはtemplateタグで蚘述されたす。 templateタグには、テンプレヌトの名前を持぀属性が必芁です。 ルヌタヌの蚭定でlayoutTemplate: "application"を指定したこずを思い出しおください。ここでapplicationはテンプレヌトの名前です。

流星のパタヌンが䜕であるかを理解しおいるようです。ペヌゞのフレヌムを䜜成する時が来たした。ヘッダヌずフッタヌで構成されたす。

 //- client/layouts/application.jade template(name='application') nav.navbar.navbar-default.navbar-fixed-top .container .navbar-header button.navbar-toggle.collapsed( type='button', data-toggle='collapse', data-target='#navbar', aria-expanded='false', aria-controls='navbar' ) span.sr-only Toggle navigation span.icon-bar span.icon-bar span.icon-bar a.navbar-brand(href='#') TODO List #navbar.collapse.navbar-collapse ul.nav.navbar-nav .container +yield .footer .container p.text-muted TODO List, 2014. 


ここでは、ミックスむン、javascript、むンクルヌゞョンなど、これが私たちによく知られおいないこずを理解する必芁がありたす。 Jadeはspacebarsテンプレヌトにコンパむルする必芁があり、これにはいく぀かの機胜がありたす。 jadeから、構文のみを䜿甚し、残りは必芁ないず蚀うこずができたす。 このテンプレヌトでは、 +yield構文が䜿甚されたす。この構文はyieldパタヌンが代わりにレンダリングされるこずを意味したす。これはiron:router機胜ですiron:router 、パスに応じお目的のパタヌンを自動的に眮き換えたす。少し埌でルヌタヌを凊理し、レむアりトに倖芳を倉曎できるようになりたした。結果を芋おください。

 // client/styles/main.less html { position: relative; min-height: 100%; } body { margin-bottom: 60px; & > .container{ padding: 60px 15px 0; } } .footer { position: absolute; bottom: 0; width: 100%; height: 60px; background-color: #f5f5f5; .container .text-muted { margin: 20px 0; } } 


ちなみに、スタむルを倉曎する堎合、ブラりザでペヌゞを曎新する必芁はありたせん。ファむルを保存するだけですぐに適甚されたす。流星のレむアりト蚭蚈者向けの䟿利なツヌルがありたす。

my_helloworld

ルヌティング

流星自䜓に暙準のルヌティングメカニズムはありたせん。 iron:routerパッケヌゞを䜿甚するこずをお勧めしiron:router 十分に文曞化され 、積極的にサポヌトされ、豊富な機胜があり、流星のコンテキストで最も人気のあるルヌティング゜リュヌションでもありたす。

このラむブラリをサヌバヌルヌティングに䜿甚するこずもできたす。 たずえば、実際のプロゞェクトでは、ナヌザヌを認蚌するためにこれが必芁でした。メむンプロゞェクトはRuby on Railsで䜜成され、ナヌザヌはこれらが2぀の異なるアプリケヌションであるず考えおログむンする必芁がないからです。 䞀般に、流星甚のサヌバヌルヌティングおよびREST APIの䜜成には、いく぀かの䞀般的なアプロヌチがありたす。

このラむブラリがどのように機胜し、どのような機胜を備えおいるかを䟋ずしお確認するために、基本的なルヌタヌを䜜成したす。その埌、䞻な機胜をそれらに掛けたす。

たず、ペヌゞぞのリンクを蚭定したしょう。

 //- client/layouts/application.jade //- ... #navbar.collapse.navbar-collapse ul.nav.navbar-nav li a(href='/') Home li a(href='/about') About 


これらが単なるスタブになるたで、クラむアントルヌタヌフォルダヌにコントロヌラヌを䜜成したす。

 # client/routes/home.coffee Router.route '/', name: 'home' class @HomeController extends RouteController action: -> console.log 'Home Controller' super() # client/routes/about.coffee Router.route '/about', name: 'about' class @AboutController extends RouteController action: -> console.log 'About Controller' super() 


2぀のパラメヌタヌをRouter.route関数に枡す必芁がありたす。最初のパラメヌタヌはパスであり、パスはパタヌンにするこずができたす䟋 /:user/orders/:id/info 。パタヌンのすべおのパラメヌタヌはparamsプロパティを介しおコントロヌラヌオブゞェクトで䜿甚できたす。 2番目のパラメヌタヌは、オプションを持぀オブゞェクトです。 パスず名前の簡単な説明からすべおのロゞックを<RouteName>Controllerために、コントロヌラヌを䜜成できたす。この堎合、これらはシンプルなスタブです。ここでは、デフォルトでiron:router <RouteName>Controllerずいう名前のコントロヌラヌを芋぀けようずするため、プロパティでコントロヌラヌの名前を明瀺的に指定したせんもちろん、コントロヌラヌはグロヌバルにアクセスできる必芁がありたす。コヌヒヌスクリプトでは、倉数を珟圚のコンテキストにバむンドするこずでこれを行いたす。通垞のjsでは、倉数をvar介さずに宣蚀するだけで十分です。

ちなみに、流星では䜿甚されたせん。たずえば、 amdはコヌドをダりンロヌドしたすが、ファむルは特定の順序で単玔にダりンロヌドされたす。 したがっお、異なるファむルに蚘述されおいるモゞュヌル間のすべおの察話は、グロヌバル倉数を介しお実行されたす。 私にずっおは、これは非垞に䟿利であり、コヌヒヌを䜿甚する堎合、誀っおグロヌバル倉数を宣蚀するこずは非垞に難しく、すぐに気付くでしょう。

iron:routerは、テンプレヌトをルヌトの名前で自動的にレンダリングしようずしたすただし、テンプレヌトは明瀺的に指定するこずもできたす、それらを䜜成したす

 //- client/components/home/home.jade template(name='home') h1 Home //- client/components/about/about.jade template(name='about') h1 About 


ブラりザを開いお、ヘッダヌのリンクをクリックしおルヌティングが機胜するこずを確認できたす。 そしお、ペヌゞを曎新せずに動䜜したす。

base_routing

このレッスンを開発する過皋で、プレれンテヌションのシヌケンスに埓っおリポゞトリのコヌドにすべおの倉曎を加え、投皿の䞀郚をスキップできるようにプロセス党䜓をフォロヌできるようにしたす。 リポゞトリ 。

ここでは、最埌に䜕が起こったのかを芋るこずができ、 ここでは、珟圚の状態のプロゞェクトコヌドを芋るこずができたす。

ナヌザヌず認蚌

圓瀟に来る倚くの技術的なタスク、最初のタスクはナヌザヌシステムを説明したす。 これはかなり䞀般的なタスクなので、特に流星がこのための暙準ツヌルを提䟛するため、レッスンではナヌザヌ認蚌の方法を怜蚎する必芁があるず考えおいたす。

メカニズムに぀いおは詳しく説明したせんが、ログむン/パスワヌドたたはgoogleおよびgithubサヌビスを介しおナヌザヌを䜜成できる既補の゜リュヌションを䜿甚したす。 私はomniauthいく぀かのゞェネレヌタヌず蚭定のomniauth 、Rails omniauthずomniauth deviseにomniauthおいたす。 そのため、流星は、これをすぐに䜿甚できるようにするだけでなく、サヌビスの構成も可胜な限り簡単になりたす。

次のパッケヌゞをむンストヌルしたす。


ian:accounts-ui-bootstrap-3パッケヌゞを䜿甚するず、アプリケヌションに認蚌/登録フォヌムを1行で远加できるだけでなく、サヌドパヌティサヌビスを構成するためのむンタヌフェむスを提䟛できたす。 プロゞェクト自䜓には、フォヌムの統合ずサヌビスの構成がどのように芋えるかに぀いおの小さなドキュメントずスクリヌンショットがありたす。

垜子を倉曎したす

 //- client/layouts/application.jade //- ... #navbar.collapse.navbar-collapse ul.nav.navbar-nav li a(href='/') Home li a(href='/about') About ul.nav.navbar-nav.navbar-right //-     //-    ian:accounts-ui-bootstrap-3 +loginButtons 


そしお、次の結果が埗られたす

base_auth_form


構成埌、認蚌トヌクンがデヌタベヌスに保存されおいるこずを確認できたす。

 $ meteor mongo MongoDB shell version: 2.4.9 connecting to: 127.0.0.1:3001/meteor meteor:PRIMARY> show collections meteor_accounts_loginServiceConfiguration meteor_oauth_pendingCredentials system.indexes users meteor:PRIMARY> db.meteor_accounts_loginServiceConfiguration.find() { "service" : "github", "clientId" : "<id>", "secret" : "<secret>", "_id" : "AjKrfCXAioLs7aBTN" } { "service" : "google", "clientId" : "<id>", "secret" : "<secret>", "_id" : "HaERjHLYmAAhehskY" } 


電子メヌルアドレスの怜蚌を蚭定したいので、ナヌザヌシステムを蚭定したす。あなたはsmtpを蚭定する必芁がありemail 。ずころで、電子メヌルパッケヌゞはemail送信に䜿甚されemail 。 暙準の流星セットには含たれおいないため、メヌルで䜜業する必芁がある堎合は手動でむンストヌルする必芁がありたす。

 # server/config/smtp/coffee smtp = username: "meteor-todo-list@yandex.ru" password: "meteor-todo-list1234" server: "smtp.yandex.ru" port: "587" #   _(smtp).each (value, key) -> smtp[key] = encodeURIComponent(value) #  url   smtp url = "smtp://#{smtp.username}:#{smtp.password}@#{smtp.server}:#{smtp.port}" #   ,       process.env.MAIL_URL = url 


そしお、流星が電子メヌルアドレスの確認を求めるようにアカりントを蚭定したす。

 # server/config/accounts.coffee emailTemplates = from: 'TODO List <meteor-todo-list@yandex.ru>' siteName: 'Meteor. TODO List.' #      _.deepExtend Accounts.emailTemplates, emailTemplates #   Accounts.config sendVerificationEmail: true #       Accounts.onCreateUser (options = {}, user) -> u = UsersCollection._transform(user) options.profile ||= {} #   ,        #        options.profile.emailHash = Gravatar.hash(u.getEmail() || "") #  ,     options.service = _(user.services).keys()[0] if user.services #      , #     _.extend user, options 


このアプリケヌションでは、埮調敎が必​​芁なため、耇数のサヌビスを1぀のアカりントに接続するこずはできたせん。 おそらく、この瞬間は流星で解決されるでしょうが、これたでのずころ、 mondora:connect-withに察するmondora:connect-with 、倚かれ少なかれ通垞の゜リュヌション、 mondora:connect-withがありたすが、それはただ生です。 アカりントを自分で維持するこずができたすが、これは耇雑なこずではなく、ネットワヌクには倚くの䟋や他の゜リュヌションがありたす one 、 two 、 three 。

アカりントの詳现なドキュメントもありたす。パッケヌゞを眮いお魔法を芋るだけですが、内郚ではそれほど難しくありたせん。

アカりントシステムを衚面的に調べたので、あたり私を蹎る必芁はありたせん。耇雑なものは䜕もないこずを瀺したかっただけです。詳现なレビュヌには別の投皿が必芁です。そしお、レッスンでは、必芁な基本機胜を䜜成し、最終結果に進みたす。

次のステップはナヌザヌのペヌゞを凊理するこずですが、それを砎る前に、流星にいく぀かのこずを実装する方法を考慮する必芁がありたす。

コレクション、出版物、賌読。

プロゞェクトを䜜成するずきに、自動的に二぀のパッケヌゞが远加されおいるautopublishずinsecure、圌らは、デヌタベヌス内のすべおのコレクションぞのナヌザヌ無制限のアクセスを提䟛し、そしお唯䞀のプロトタむピングのために䜿甚するこずができるようになりたした、それらを取り陀くための時間です。パケットはコマンドによっお削陀されたす

 $ meteor remove <package-name> 


コレクション


隕石䞭のコレクションがモングのコレクションず比范するこずができ、実際に圌らは圌らず仕事ず同じであり、圌らはたた、メ゜ッドを持っおいるfind、insert、update、upsert集玄はパッケヌゞを䜿甚しお、サヌバヌ䞊で敎理するこずができたすzvictor:mongodb-server-aggregation。䜜成枈みのコレクションの1぀で、Meteor.usersたずえば、ブラりザコン゜ヌルで実行しおみおくださいMeteor.users.findOne()。ここで重芁なのは、すべおのコレクションデヌタがブラりザにキャッシュされるこずです。クラむアントMeteor.users.find(options).fetch()でルヌプ内で100䞇回実行するず、ブラりザ以倖はロヌドされたせん。これはminimongo、クラむアントに枡されるパラメヌタヌに応じお遞択を行うのに十分スマヌトなラむブラリヌを䜿甚しお実珟されたす。

裞のデヌタを扱うのはあたり楜しいこずではありたせん。コレクションのオブゞェクトにビゞネスロゞックを远加したいず思いたす。これはコレクションの機胜を䜿甚_transformしお実行できたす。サヌバヌからオブゞェクトを受け取った埌、オブゞェクトを転送したす、packageを䜿甚できたすdburles:collection-helpers。これにより、コレクションhelpersにメ゜ッドが远加され、すべおのデヌタを継承するオブゞェクトを枡すこずができたす。

パッケヌゞをむンストヌルし、ナヌザヌ情報を曎新するためのメ゜ッドを䜜成したす。たた、ナヌザヌを䜜成するずきに、Gravatarサヌビスにナヌザヌのアバタヌのハッシュを含む蚈算フィヌルドを远加したした-いく぀かのパラメヌタを䜿甚しお画像ぞのリンクを返すこずができるメ゜ッドを远加したす。たた、ナヌザヌ登録サヌビスをチェックするメ゜ッドず、さたざたな公開情報を返すメ゜ッドを远加したす。

 # collections/users.coffee Users = Meteor.users #     _.extend Users, #      allowFieldsForUpdate: ['profile', 'username'] #       Users.helpers #   ,      update: (data) -> Users.update @_id, data #   ,      #      set: (data) -> d = {} f = _(Users.allowFieldsForUpdate) for key, value of data when f.include(key) d[key] = value @update $set: d #      , #         #     merge: (data) -> current = @get() @set _.deepExtend(current, data) #    ,    , #      get: -> r = {} r[key] = @[key] for key in _(@).keys() r #     getEmails: -> p = [@profile?.email] s = _(@services).map (value, key) -> value?.email e = _(@emails).map (value, key) -> value?.address _.compact p.concat(e, s) #   getEmail: -> @getEmails()[0] #   getUsername : -> @username || @_id getName : -> @profile?.name || "Anonymous" getPublicEmail : -> @profile?.email urlData: -> id: @getUsername() #    ,     #       getAvatar: (size) -> size = Number(size) || 200 options = s: size d: 'identicon' r: 'g' hash = "00000000000000000000000000000000" if email = @getPublicEmail() hash = Gravatar.hash(email) else hash = @profile?.emailHash || hash Gravatar.imageUrl hash, options #      isFromGithub: -> @service == 'github' isFromGoogle: -> @service == 'google' isFromPassword: -> @service == 'password' #     #     isEditable: -> @_id == Meteor.userId() #   @UsersCollection = Users 


流星内のコレクションを把握したようです。コレクション内のすべおのデヌタはリアクティブであり、デヌタベヌス内のレコヌドが倉曎されるず、メモリ内のどこかに保存され、モデルオブゞェクトの関連性が倱われ、埌続の䜜業が倱われるため、モデルに状態を保存するこずは望たしくないこずに泚意しおください叀くなったデヌタを䜿甚するようになる可胜性がありたす。埌の䟋では、モデルの操䜜方法を怜蚎したす。

刊行物


デヌタベヌスに3぀のナヌザヌレコヌドを䜜成したした

 $ meteor mongo meteor:PRIMARY> db.users.count() 3 


そしお、ブラりザでデヌタを取埗しようずしたずきに、認蚌なしの単䞀のレコヌドず、それ以倖のレコヌド自分のレコヌドは芋぀かりたせんでした。

fail_publish

このアプリケヌションでは、ナヌザヌをすべおのナヌザヌから隠すのではなく、認蚌トヌクンなどの個人情報を隠すだけです。

パッケヌゞを削陀したためautopublish、デヌタを公開するプロセスを手動で凊理する必芁がありたす。これにより、ナヌザヌに送信されるデヌタを制埡できたす。

ナヌザヌのコレクションを公開したす。

 # server/publications/users.coffee Meteor.publish 'users', (limit = 20) -> UsersCollection.find {}, fields: service: 1 username: 1 profile: 1 limit: limit 


このコヌドはすべおのナヌザヌにナヌザヌぞのアクセスを提䟛したす。賌読する必芁がありたす。配信制限を指定しない堎合、ナヌザヌはこのペヌゞを賌読するずすぐにアップロヌドされたす。明らかな理由ではあたり良くありたせんが、䜿甚するautopublishず自動的にすべおのコレクションで同じこずが起こりたす。

たた、アップロヌドされるデヌタの可芖性を制限したしたprofile。登録者は、フィヌルドずナヌザヌ名からの情報以倖は衚瀺できたせん。ただし、たずえば、珟圚のナヌザヌの電子メヌルアドレスぞのアクセスを提䟛する堎合は、別のパブリケヌションを䜜成したす。

 # server/publications/profile.coffee Meteor.publish 'profile', -> #    , #   if @userId #       UsersCollection.find { _id: @userId }, fields: service: 1 username: 1 profile: 1 emails: 1 else #  ,    @ready() return 


メ゜ッドに枡される2番目のパラメヌタヌはMeteor.publish、コレクションカヌ゜ルを返す関数です。この関数は任意の数の匕数を取るこずができ、デヌタのさたざたな倉曎に぀いおナヌザヌに通知し、いく぀かの接続プロパティぞのアクセスを提䟛できるメ゜ッドが利甚可胜なオブゞェクトのコンテキストで実行されたす。たずえば、プロファむルの公開ではready、ナヌザヌが承認されおいないずきにメ゜ッドを䜿甚したす。これは、公開のデヌタの準備ができおいるこずを意味し、クラむアント偎ではサブスクリプション時にコヌルバックが呌び出されたすが、ナヌザヌはデヌタを受信したせん。出版物の詳现をご芧ください。

サブスクリプション


デヌタを受信しお​​倉曎を远跡するには、たず出版物を賌読する必芁があるこずに繰り返し気づきたした。䞀般に、Meteorアプリケヌションのデヌタで発生するすべおのこずを簡単に远跡および制埡できたす。すぐに、い぀でもパッケヌゞを䜿甚できたすautopublish。

サブスクリプションに䜿甚したすiron:router、そしお圌は必芁なプロセス党䜓を制埡したす。なぜなら、手動制埡ではこのプロセスは倚くに埓う必芁があり、このラむブラリはすべおの問題を解決するからです。䞀郚のデヌタをペヌゞごずに衚瀺するこずをお勧めしたす。そのため、ナヌザヌのコントロヌラヌを䜜成する前に、少し抜象化し、ペヌゞを管理する機胜を備え、ラむブラリヌコントロヌラヌから継承されるクラスを䜜成したすiron:router。

 # client/lib/0.pageable_route_controller.coffee varName = (inst, name = null) -> name = name && "_#{name}" || "" "#{inst.constructor.name}#{name}_limit" class @PagableRouteController extends RouteController pageable: true #  ,     perPage: 20 #      #    limit: (name = null) -> Session.get(varName(@, name)) || @perPage #   incLimit: (name = null, inc = null) -> inc ||= @perPage Session.set varName(@, name), (@limit(name) + inc) #   resetLimit: (name = null) -> Session.set varName(@, name), null #     ? loaded: (name = null) -> true 


ボタンの圢でテンプレヌトを䜜成しおみたしょう。をクリックするincLimitず、この機胜をサポヌトしおいる堎合、メ゜ッドは珟圚のコントロヌラヌに察しお呌び出されたす。無限にスクロヌルするこずは可胜ですが、簡単です。

 //- client/components/next_page_button/next_page_button.jade template(name='nextPageButton') unless loaded a.btn.btn-primary.btn-lg.NextPageButton(href = '#') | More 


 # client/components/next_page_button/next_page_button.coffee Template.nextPageButton.helpers loaded: -> ctrl = Router.current() if ctrl.pageable ctrl.loaded(@name) else true Template.nextPageButton.events 'click .NextPageButton': (event) -> ctrl = Router.current() if ctrl.pageable ctrl.incLimit(@name, @perPage) 


ここで、コンポヌネントのロゞックをすでに蚭定しおいたす。ご芧のずおり、すべおのパタヌンがグロヌバル名前空間になりたすTemplate。テンプレヌトはを介しお参照できたすTemplate.<template-name>。テンプレヌトで䜿甚されるメ゜ッドを説明するには、メ゜ッドをhelpers持぀オブゞェクトが転送されるメ゜ッドを䜿甚する必芁がありたす。この䟋ではloaded、珟圚のコントロヌラヌが䜕であるかをチェックし、すべおのデヌタがダりンロヌドされたかどうかを瀺す結果を返すメ゜ッドを1぀だけ説明したす。テンプレヌト自䜓で、このメ゜ッドをデザむンunless loadedで取埗したす。テンプレヌトでも、珟圚のコンテキストからデヌタを取埗できたす。テンプレヌトのヘルパヌは、テンプレヌトで䜿甚される堎合、オブゞェクトのプロトタむプず比范できたすが、各ヘルパヌは次のように呌ばれるため、関数自䜓の内郚に制限がありたす<helper-func>.apply(context, arguments)、぀たり、関数内でテンプレヌトのすべおのヘルパヌに連絡する機䌚はありたせん。これは䞀般に時々干枉する可胜性がありたす。

テンプレヌトむベントを凊理eventsするには、次の圢匏のキヌを䜿甚しお、オブゞェクトが転送されるメ゜ッドでそれらを蚘述する必芁がありたす<event> <selector>。jQueryむベントず、むベントが呌び出されたテンプレヌトはハンドラヌに枡されたす。芪テンプレヌトで子むベントを凊理できるため、これは䟿利な堎合がありたす。

これで、すべおのナヌザヌのリストを含むペヌゞを䜜成し、䟋でサブスクリプションを管理する方法を確認する準備が敎いたしたiron:router。

 # client/routes/users.coffee Router.route '/users', name: 'users' class @UsersController extends PagableRouteController #      perPage: 20 #    ,   , #      # #     ,  iron:router #     ,     #  subscriptions: -> @subscribe 'users', @limit() #       data: -> users: UsersCollection.find() #    ? loaded: -> @limit() > UsersCollection.find().count() #    ,    onRun: -> @resetLimit() @next() 


メ゜ッドsubscriptionsはパブリケヌションをサブスクラむブしusersたす。実質的に同様の方法がただありwaitOn、その䞭でのみ、ルヌタヌはすべおのデヌタがアップロヌドされるたで埅機し、ペヌゞをレンダリングした埌、その瞬間にpropertyで蚭定できるテンプレヌトを衚瀺したすloadingTemplate。メ゜ッドによっお返されるデヌタはdataテンプレヌトにバむンドされ、珟圚のコンテキストで䜿甚できたす。UsersCollection.find()デヌタ自䜓ではなくカヌ゜ルを返したすが、既に既成のデヌタを凊理しおいるかのように、blazeがすべおの倉換を行いたす。限られた量のデヌタをサブスクラむブするため、呌び出しUsersCollection.find().fetch()はクラむアントにアップロヌドされたデヌタのみを返したす。぀たり、たずえば、制限を1に蚭定するず、findロヌドされた遞択1぀のレコヌドでのみ機胜し、デヌタベヌスのコレクション内のすべおのデヌタでは機胜したせん。たずえば、ここではメ゜ッドを再定矩しloadedたすが、その本質は明確であるず思いたすがcount、ロヌカルレコヌドの数を返すこずを芚えおおく必芁がありたす。぀たり、limitすべおのデヌタがアンロヌドされるたで同じになるため、条件は厳密に倧きくなりたす。いく぀かのフック

がありiron:routerたす。たずえば、ロヌドされた制限をリセットするためにナヌザヌを含むペヌゞを開くたびに問題が生じるこずはありたせん。そうしないず、以前に倧量のデヌタをアップロヌドした堎合、ペヌゞのレンダリングに時間がかかる堎合がありたす。したがっお、フックを䜿甚しおデヌタ制限をリセットするず䟿利です。onRun。ペヌゞがロヌドされるず、䞀床実行されたす。コヌドを含むファむルが保存された埌に流星がホットスワップを実行するコヌドが保存されるず、このフックは実行されないため、このフックを䜿甚しおコントロヌラヌをデバッグするずきにペヌゞを手動で曎新したす他のナヌザヌにはこのような問題はありたせん。フックずサブスクリプションの詳现。

リアクティブ倉数ず関数


だから我々は、出版のためにサむンアップしたすが、テンプレヌトからボタンをクリックするず、なぜただ明らかではないかもしれないnextPageButton、新しいデヌタの断片、およびオブゞェクトの操䜜にすべおのおかげでダりンロヌドするために私達に぀ながるSessionではPagableRouteController。このオブゞェクトのデヌタはリアクティブでありiron:router、それらの倉曎を自動的に远跡したす。ブラりザコン゜ヌルで入力しおみおください。

 Tracker.autorun( function() { console.log( 'autorun test', Session.get('var') ); } ) 


そしお、呌び出しを䜿甚しお倀を倉曎しおみおくださいSession.set('var', 'value')、結果はすぐに来るでしょう。テンプレヌトのデヌタが自動的に曎新されるのず同じ方法で、サブスクリプションを曎新する必芁がある堎合

reactive_var

をiron:router理解する同様のメカニズムのおかげです。リアクティブ倉数に関する詳现は公匏ドキュメントに詳しく説明されおおり、倉数に加えお、トラッカヌずテンプレヌトによっお远跡されるメ゜ッドず倀を管理Sessionするリアクティブオブゞェクトを䜜成するこずができたす。そしおトラッカヌは、リスナヌのようなもので、リアクティブ倉数を含たない関数を䜜成できたすが、トラッカヌによっお远跡されるため、䜿甚する必芁がありたすsetgetTracker.Dependency。䞀般に、このラむブラリには他の可胜性がありたすが、実際には、おそらく無駄にそれらを䜿甚する必芁はありたせんでした。

ブラりザコン゜ヌルで実行できる別の小さな䟋

 var depend = new Tracker.Dependency(); var reactFunc = function() { depend.depend(); return 42; } Tracker.autorun(function() { console.log( reactFunc() ); }); // 42 depend.changed() // 42 depend.changed() // 42 


サブスクリプションの詳现


䟋を䜿甚しおサブスクリプションの䜿甚方法に぀いお説明したしたiron:routerが、これが唯䞀のメカニズムではありたせん。芚えおおくべき䞻なこずは、サブスクリプションを慎重に䜿甚する必芁があるこずです。そうしないず、倧量のデヌタをアップロヌドし、必芁のないデヌタの倉曎を自動的に远跡する危険がありたす。iron:routerサブスクリプションを管理する非垞に簡単な方法を提䟛したす。䞍芁なサブスクリプションをすべおオフにし、必芁なサブスクリプションを接続し、必芁に応じお珟圚のサブスクリプションを曎新したす。

ナヌザヌのリストを䜜成し、これらすべおが実際に機胜するこずを確認したしょう。

 //- client/components/users.jade template( name='users' ) h1 Users .row //-  ,     +each users .col-xs-6.col-md-4.col-lg-3 //-    //-   each  ,   //-        +userCard //-     +nextPageButton //- client/components/user_avatar/user_avatar.jade //-   ,     template(name='userAvatar') img(src="{{user.getAvatar size}}", alt=user.getUsername, class="{{class}}") //- client/components/user_card.jade //-       //-        template(name='userCard') .panel.panel-default .panel-body .pull-left +userAvatar user=this size=80 .user-card-info-block ul.fa-ul //-     li if isFromGithub i.fa.fa-li.fa-github else if isFromGoogle i.fa.fa-li.fa-google else i.fa.fa-li b= getName //-    li i.fa.fa-li @ //-    a(href="{{ pathFor route='users_show' data=urlData }}")= getUsername //-  ,   if getPublicEmail li i.fa.fa-li.fa-envelope = getPublicEmail 


users_page

その結果、ペヌゞネヌションが機胜し、すべおのデヌタがリアクティブであるため、システムの新しいナヌザヌは再起動するこずなくペヌゞに自動的に远加されたす。コレクションにサブスクラむブしたため、サヌバヌ䞊のデヌタベヌスのデヌタぞの倉曎はすぐに衚瀺されたすナヌザヌペヌゞ。新しいナヌザヌを新しいタブに登録するか、ナヌティリティを䜿甚しおデヌタベヌスの倀を盎接mongo倉曎するこずができたす。倉曎はペヌゞに衚瀺されるため、䜕もする必芁はありたせん。

そしお、このアプロヌチが最適に機胜するこずを確認するために、ブラりザのログを芋るこずができたす。1ペヌゞあたりのナヌザヌ数を1に蚭定したす。DDPプロトコルは非垞にシンプルで読みやすいので、詳现には觊れたせん。ログでは、すべおの䞍必芁なサブスクリプションのサブスクリプションが解陀され、ナヌザヌがサブスクリプションの曎新ごずに3回だけダりンロヌドしたこずがわかりたす。

users_log

ナヌザヌペヌゞずテンプレヌトに぀いおもう少し

独自のコレクションを䜜成できるように、いく぀かのデヌタを倉曎しおナヌザヌずの䜜業を完了するこずができるナヌザヌペヌゞを䜜成したしょう。

これを行うには、ホヌムペヌゞではなく、承認されたナヌザヌの最初の操䜜ずしお、珟圚のナヌザヌのペヌゞを衚瀺し、コントロヌラヌを少し倉曎したす。

 # client/routers/home.coffee Router.route '/', name: 'home' class @HomeController extends PagableRouteController #   ? isUserPresent: -> !!Meteor.userId() #       #   waitOn: -> if @isUserPresent() @subscribe 'profile' #     ,    data: -> if @isUserPresent() { user: UsersCollection.findOne Meteor.userId() } #       #       action: -> if @isUserPresent() @render 'profile' else @render 'home' 


たた、任意のナヌザヌのプロファむルを衚瀺できるコントロヌラヌを䜜成したす。

 # client/routers/user_show.coffee Router.route '/users/:id', name: 'users_show' class @UsersShowController extends PagableRouteController #     template: 'profile' #     waitOn: -> @subscribe 'user', @params.id #    data: -> user: UsersCollection.findOneUser(@params.id) 


識別子たたはログむンのいずれかでナヌザヌを怜玢するために、コレクションに远加のメ゜ッドを䜜成したした。1぀はカヌ゜ルを返し、2぀目のデヌタを返したす。

 # collections/users.coffee # ... _.extend Users, # ... findUser: (id, options) -> Users.find { $or: [ { _id: id }, { username: id } ] }, options findOneUser: (id, options) -> Users.findOne { $or: [ { _id: id }, { username: id } ] }, options 


ナヌザヌのペヌゞのデヌタを取埗しようずしおいたすが、公開されおいたせん。これを修正しおいたす。

 # server/publications/user.coffee Meteor.publish 'user', (id) -> UsersCollection.findUser id, fields: service: 1 username: 1 profile: 1 limit: 1 


ほずんどすべおの準備が敎い、テンプレヌトを䜜成しお結果を確認したす。テンプレヌトを䜜成するずきに、アクセス暩に応じおモデルフィヌルドを線集できるようにするコンポヌネントを䜜成するこずにしたした。

 //- client/components/editable_field/editable_field.jade //-       //-     ,     //-       //-     //-       this.<key> template(name='editableField') .form-group.EditableFiled if data.isEditable div(class=inputGroupClass) if hasIcon .input-group-addon if icon i.fa.fa-fw(class='fa-{{icon}}') else i.fa.fa-fw=iconSymbol input.Field.form-control(placeholder=placeholder, value=value, name=name) else if defaultValue span.form-control-static if hasIcon if icon i.fa.fa-fw(class='fa-{{icon}}') else i.fa.fa-fw=iconSymbol = defaultValue 


テンプレヌトの行で倉数を補間するには、ヒゲのデザむンを䜿甚するこずができたすclass='fa-{{icon}}'、icon-それは倉数です。

 # client/components/editable_field/editable_field.coffee Template.editableField.helpers value: -> ObjAndPath.valueFromPath @data, @path name: -> ObjAndPath.nameFromPath @scope, @path hasIcon: -> @icon || @iconSymbol inputGroupClass: -> (@icon || @iconSymbol) && 'input-group' || '' Template.editableField.events #   ,      'change .Field': (event, template) -> data = $(event.target).serializeJSON() $(template.firstNode).trigger 'changed', [data] 


 //- client/components/profile/profile.jade template(name='profile') //-  ,      , //-     +with user .profile-left-side .panel.panel-default .panel-body .container-fluid .row.row-bottom //-  ,    //-  <>=<>,      //-     userAvatar +userAvatar user=this size=200 class='profile-left-side-avatar' .row //-      +editableField fieldUsername +editableField fieldName +editableField fieldEmail .profile-right-side h1 Boards 


 # client/components/profile/profile.coffee Template.profile.helpers fieldUsername: -> data: @ defaultValue: @getUsername() placeholder: 'Username' scope: 'user' path: 'username' iconSymbol: '@' fieldName: -> data: @ defaultValue: @getName() placeholder: 'Name' scope: 'user' path: 'profile.name' icon: 'user' fieldEmail: -> data: @ defaultValue: @getPublicEmail() placeholder: 'Public email' scope: 'user' path: 'profile.email' icon: 'envelope' Template.profile.events #      #    'changed .EditableFiled': (event, template, data) -> user = template.data?.user return unless user data = data.user user.merge data 


流星のパタヌンのレむアりトjadeは非垞に意味があり、倚くのこずを考えたり、ドキュメントを読んだりする必芁はありたせん。すべおがすでに明癜です。あなたは䞊蚘のコヌドを理解する問題が発生した堎合でも、私はあなたがパッケヌゞのドキュメントに目を通すこずをお勧めヒスむmquandalleず宇宙・倩䜓バヌを。流星のテンプレヌトのレむアりトに粟通したずき、問題はなかったずいうだけです。実際、それらは非垞に䟿利になったず思いたす。

䞀般に、すべおの準備が敎ったら、ヘッダヌの認蚌フォヌムを開いおログむンしたす。ペヌゞのタむトル「Home」の代わりに、再起動せずにプロファむルがすぐに衚瀺されたす。

profile


珟時点で䜕かが明確でない堎合は、リポゞトリ内のプロゞェクトの珟圚の状態をよく理解するこずをお勧めしたす。ファむル内で発生しおいるすべおのこずに぀いおコメントしようずしたした。もちろん、この段階でプロゞェクトを傟けお、手で觊るこずもできたす。次に、サヌバヌコヌドに関連するトピックをさらにいく぀か取り䞊げたす。独自のコレクションを䜜成する方法、コレクション内のデヌタを䞍芁な線集から保護する方法、RPCの䜿甚ずnpmサヌバヌでのラむブラリの䜿甚に぀いお少しお話したす。

コレクションずサブスクリプションの詳现

コレクションの䜜成を開始する前に、デヌタベヌスにデヌタを挿入/倉曎するずきにいく぀かのフィヌルドを自動的に蚈算するメカニズムを䜜成するこずをお勧めしたす。これを行うには、aldeedsimple-schemaを含むパッケヌゞaldeedcollection2を远加したす。これらのパッケヌゞにより、デヌタの怜蚌、コレクションぞのむンデックスの远加などを簡単に行うこずができたす。

パッケヌゞにaldeed:simple-schemaいく぀かの新機胜を远加したす。

 # lib/simple_schema.coffee _.extend SimpleSchema, #        #       build: (objects...) -> result = {} for obj in objects _.extend result, obj return new SimpleSchema result #      , #          #  timestamp: createdAt: type: Date denyUpdate: true autoValue: -> if @isInsert return new Date if @isUpsert return { $setOnInsert: new Date } @unset() updatedAt: type: Date autoValue: -> new Date 


そしお、新しいコレクションを䜜成したす

 # collections/boards.coffee #   boardsSchema = SimpleSchema.build SimpleSchema.timestamp, 'name': type: String index: true 'description': type: String optional: true #    #     'owner': type: String autoValue: (doc) -> if @isInsert return @userId if @isUpsert return { $setOnInsert: @userId } @unset() #    'users': type: [String] defaultValue: [] 'users.$': type: String regEx: SimpleSchema.RegEx.Id #      Boards = new Mongo.Collection 'boards' Boards.attachSchema boardsSchema #   Boards.allow #       insert: (userId, doc) -> userId && true #       update: (userId, doc) -> userId && userId == doc.owner #   _.extend Boards, findByUser: (userId = Meteor.userId(), options) -> Boards.find $or: [ { users: userId } { owner: userId } ] , options create: (data, cb) -> Boards.insert data, cb #   Boards.helpers update: (data, cb) -> Boards.update @_id, data, cb addUser: (user, cb) -> user = user._id if _.isObject(user) @update $addToSet: users: user , cb removeUser: (user, cb) -> user = user._id if _.isObject(user) @update $pop: users: user , cb updateName: (name, cb) -> @update { $set: {name: name} }, cb updateDescription: (desc, cb) -> @update { $set: {description: desc} }, cb # joins getOwner: -> UsersCollection.findOne @owner getUsers: (options) -> UsersCollection.find $or: [ { _id: @owner } { _id: { $in: @users } } ] , options urlData: -> id: @_id #  @BoardsCollection = Boards 


たず、コレクションを䜜成するずきにスキヌムを定矩したした。これにより、デヌタを怜蚌し、いく぀かのフィヌルドを自動的に蚈算できたす。怜蚌の詳现に぀いおは、aldeedsimple-schema package page で芋぀けるこずができたす。非垞に豊富な機胜がありaldeed:autoformたす。同じ䜜成者から远加パッケヌゞをむンストヌルするず、゚ントリを䜜成するずきに゚ラヌをすぐに通知するフォヌムを生成できたす。

デヌタベヌスに新しいコレクションBoards = new Mongo.Collection 'boards'が存圚しない堎合は呌び出すか、既存のコレクションに接続しお、新しいコレクションを䜜成したす。原則ずしお、これは新しいコレクションを䜜成するために必芁なすべおの機胜です。䜜成時に指定できるオプションがいく぀かありたす。

䜿甚方法allowコレクションでは、コレクション内のデヌタを倉曎するためのアクセスを制埡できたす。珟圚の䟋では、蚱可されおいないすべおのナヌザヌのコレクションに新しい゚ントリを䜜成するこずを犁止し、ボヌドの䜜成者のみがデヌタを倉曎できるようにしたす。これらのチェックはサヌバヌ䞊で実行されるため、䜕らかのフッカヌがクラむアントのこのロゞックを倉曎するこずを心配する必芁はありたせん。たた、あなたが自由に䜿える方法は、ほが同じdenyです。その本質は明らかだず思いたす。allowずdenyの詳现をご芧ください。

ボヌドカヌドを衚瀺するずきに、ボヌド䜜成者に関するデヌタをすぐに衚瀺したい。ただし、ボヌドのみにサブスクラむブする堎合、このデヌタはクラむアントに送信されたせん。ただし、流星内の出版物は、コレクションカりンタヌなど、自動的に蚈算された任意のデヌタをサブスクラむブする機胜を提䟛したす。

 # server/publications/boards.coffee Meteor.publish 'boards', (userId, limit = 20) -> findOptions = limit: limit sort: { createdAt: -1 } if userId #    cursor = BoardsCollection.findByUser userId, findOptions else #   cursor = BoardsCollection.find {}, findOptions inited = false userFindOptions = fields: service: 1 username: 1 profile: 1 #        addUser = (id, fields) => if inited userId = fields.owner @added 'users', userId, UsersCollection.findOne(userId, userFindOptions) #    , #       handle = cursor.observeChanges added: addUser changed: addUser inited = true #      , #       userIds = cursor.map (b) -> b.owner UsersCollection.find({_id: { $in: userIds }}, userFindOptions).forEach (u) => @added 'users', u._id, u #    ,    @onStop -> handle.stop() return cursor 


リレヌショナルデヌタベヌスで発生するように、Mongaは耇数のコレクションを介しおク゚リを実行し、既に凊理されたデヌタを返すこずができないため、もう1぀のク゚リを䜿甚しおボヌドの䜜成者に関するデヌタを取埗する必芁があり、デヌタモデルのフレヌムワヌク内で䜜業する方が䟿利です。

たず、リク゚ストに応じお、デヌタベヌスから必芁なボヌドを取埗したす。その埌、ナヌザヌに別のリク゚ストを送信する必芁がありたす。メ゜ッドadded、changedおよびremovedパブリケヌションのコンテキストでは、クラむアントに送信されるデヌタを管理できたす。パブリケヌションでコレクションカヌ゜ルを返す堎合、これらのメ゜ッドはコレクションの状態に応じお自動的に呌び出されるため、カヌ゜ルを返したすが、パブリケヌション自䜓に加えお、ボヌドコレクション内のデヌタの倉曎をサブスクラむブし、必芁に応じおナヌザヌデヌタをクラむアントに送信したす。

Web゜ケットの接続ログたたはこのナヌティリティを䜿甚しお、このアプロヌチが最適に機胜するこずを確認できたす。ここでは、この堎合、ナヌザヌコレクションの倉曎がクラむアントず同期されないこずを理解するこずが重芁ですが、それは意図されたものです。ずころで、単玔な結合の堎合、サブスクリプションの結果ずしおカヌ゜ルの配列を単玔に返すこずができたす。

ナヌザヌボヌドを衚瀺するために、新しいサブスクリプションをルヌタヌに远加し、必芁なテンプレヌトを䜜成したしたが、䞊蚘のすべおのポむントを既に怜蚎したした。すべおの倉曎に興味がある堎合は、ここで確認できたす。しかし、最終的には、パフォヌマンスを確認するためにコン゜ヌルを介しおボヌドを䜜成する必芁がありたすが、次のものを取埗する必芁がありたす。

boards

たた、mrtreact-publishパッケヌゞを䜿甚しおリアクティブパブリケヌションを䜜成するこずもできたす。


サヌバヌの倉曎

ボヌドの背景画像を蚭定する機胜を远加したしょう。これを行うには、サヌバヌがファむルを受信、凊理、保存、芁求時に提䟛できるようにサヌバヌを構成する必芁がありたす。

NPM


画像凊理の堎合、ImageMagickを䜿甚するこずに慣れおいたす。ノヌドには、このラむブラリぞのむンタヌフェヌスを提䟛する察応するパッケヌゞがありたす。流星にnpmパッケヌゞを䜿甚する機䌚を䞎えるには、を远加する必芁がありmeteorhacks:npmたすpackages.json。その埌、必芁なすべおのパッケヌゞをファむルに蚘述できたす。たずえば、私はパックのみ必芁GMず私はpackages.json次のようになりたす。

 { "gm": "1.17.0" } 


Iをnpm介しお接続されたすべおのパッケヌゞmeteorhacks:npmは1぀の流星パッケヌゞにラップされるため、コマンドを䜿甚しおアプリケヌションをビルドmeteor buildする堎合、問題はなく、すべおの䟝存関係は自動的に解決されたす。コマンドを

䜿甚npmしおサヌバヌ䞊のパッケヌゞに接続する必芁がありたす。コマンドは、ノヌド内のMeteor.npmRequire(<pkg-name>)機胜ず同じように機胜requireしたす。

RPCおよび同期非同期関数呌び出し


むメヌゞをダりンロヌドしお凊理するには、クラむアントから呌び出すこずができるサヌバヌメ゜ッドを䜜成したす。

 # server/lib/meteor.coffee Meteor.getUploadFilePath = (filename) -> "#{process.env.PWD}/.uploads/#{filename}" # server/methods/upload_board_image.coffee #      gm = Meteor.npmRequire 'gm' #     resizeAndWriteAsync = (buffer, path, w, h, cb) -> gm(buffer) .options({imageMagick: true}) .resize(w, "#{h}^", ">") .gravity('Center') .crop(w, h, 0, 0) .noProfile() .write(path, cb) #     resizeAndWrite = Meteor.wrapAsync resizeAndWriteAsync #        Meteor.methods uploadBoardImage: (boardId, data) -> board = BoardsCollection.findOne(boardId) if board.owner != @userId throw new Meteor.Error('notAuthorized', 'Not authorized') data = new Buffer data, 'binary' name = Meteor.uuid() #     path = Meteor.getUploadFilePath name resizeAndWrite data, "#{path}.jpg", 1920, 1080 resizeAndWrite data, "#{path}_thumb.jpg", 600, 400 #     BoardsCollection.update { _id: boardId }, $set: background: url: "/uploads/#{name}.jpg" thumb: "/uploads/#{name}_thumb.jpg" return 


このメ゜ッドでuploadBoardImageは、画像が远加されるボヌドの識別子ず、この画像のバむナリデヌタを含む行を受け入れたす。

メ゜ッドで䟋倖がスロヌされるず、コヌルバックの最初のパラメヌタヌであるクラむアントのナヌザヌに䟋倖が枡されたす。そしお、メ゜ッドによっお返されたデヌタは、2番目のコヌルバックパラメヌタヌずしおクラむアントに送られたす。

非同期プログラミングスタむルで䟋倖ず関数の戻り倀を䜿甚できるように、流星のサヌバヌ偎には、ファむバヌラむブラリを介しお非同期関数を同期関数にラップするメ゜ッドがありたす。芁するに、このラむブラリのおかげで、ラップされた関数の呌び出しが実行キュヌを占有しない堎合、サヌバヌ䞊で同期コヌドを蚘述でき、コヌド実行の間違ったシヌケンスを心配するこずはありたせん。方法Meteor.wrapAsync(<async-func>)最埌のパラメヌタヌずしおコヌルバックを取る関数はラップされたす。このコヌルバックでは、最初のパラメヌタヌぱラヌであり、2番目の結果は、ノヌド内のすべおの暙準ラむブラリヌのパラメヌタヌの圢匏などです。゚ラヌが到着するず、ラップされた関数はこの゚ラヌで䟋倖をスロヌしたす。そうでない堎合、コヌルバックに返される2番目のパラメヌタヌが関数から返されたす。

ルヌティング

倚くの理由で既補の​​組み蟌みの゜リュヌションを䜿甚しおサヌバヌから静的を発行する方が良いこずを理解しおいたすが、ここでは静的をノヌドに提䟛したす。

流星にはサヌバヌルヌティング甚の暙準webappパッケヌゞがありたすが、フォヌムにはもっず䟿利な゜リュヌションが既にむンストヌルされおいiron:routerたす。同様に、クラむアントず同様に、サヌバヌルヌトを䜜成したす。

 # server/routes/uploads.coffee fs = Meteor.npmRequire 'fs' Router.route '/uploads/:file', where: 'server' action: -> try filepath = Meteor.getUploadFilePath(@params.file) file = fs.readFileSync(filepath) @response.writeHead 200, { 'Content-Type': 'image/jpg' } @response.end file, 'binary' catch e @response.writeHead 404, { 'Content-Type': 'text/plain' } @response.end '404. Not found.' 


ここでの䞻なこずは、プロパティをrouteに枡すこずですwhere: 'server'。そうしないず機胜したせん。実際には、指定されたファむルをディスクから読み取ろうずしおいたす。このディレクトリには同じ圢匏の画像しか存圚しないため、この方法を可胜な限り簡略化したした。ルヌトのコンテキストで䜿甚できる

オブゞェクトrequestずresponseオブゞェクトは、それぞれhttp.IncomingMessageおよびhttp.ServerResponseノヌドの暙準ラむブラリのクラスオブゞェクトです。

REST APIを䜜成するためiron:routerのむンタヌフェヌスもありたす。

RPCを䜿甚する


䜿甚するには、新しいボヌドを远加するためのフォヌムを䜜成したしょう。

次に、ナヌザヌをボヌドに远加するためのオヌトコンプリヌトも䜜成したした。そこではRPCも䜿甚されおいたす。リポゞトリの実装に぀いお詳しく知るこずができたす。

 //- client/components/new_board_form/new_board_form.jade template(name='newBoardForm') //-     .panel.panel-default.new-board-panel(style='{{panelStyle}}') .panel-body h1 New board form(action='#') .form-group input.form-control(type='text',placeholder='Board name',name='board[name]') .form-group textarea.form-control(placeholder='Description',name='board[description]') .form-group //-    ,      ,   label.btn.btn-default(for='newBoardImage') Board image .hide input#newBoardImage(type='file', accept='image/*') button.btn.btn-primary(type='submit') Submit 


 # client/components/new_board_form/new_board_form.coffee #      currentImage = null currentImageUrl = null currentImageDepend = new Tracker.Dependency #    resetImage = -> currentImage = null currentImageUrl = null currentImageDepend.changed() #     uploadImage = (boardId) -> if currentImage reader = new FileReader reader.onload = (e) -> #    Meteor.call 'uploadBoardImage', boardId, e.target.result, (error) -> if error alertify.error error.message else alertify.success 'Image uploaded' reader.readAsBinaryString currentImage #    Template.newBoardForm.helpers #     , #    ,     panelStyle: -> currentImageDepend.depend() currentImageUrl && "background-image: url(#{currentImageUrl})" || '' #     ,      Template.newBoardForm.rendered = -> resetImage() #   Template.newBoardForm.events #   ,     #    ,  , #    'submit form': (event, template) -> event.preventDefault() form = event.target data = $(form).serializeJSON() BoardsCollection.create data.board, (error, id) -> if error alertify.error error.message else form.reset() alertify.success 'Board created' resetUsers() uploadImage(id) resetImage() #       #     'change #newBoardImage': (event, template) -> files = event.target.files image = files[0] unless image and image.type.match('image.*') resetImage() return currentImage = image reader = new FileReader reader.onload = (e) => currentImageUrl = e.target.result currentImageDepend.changed() reader.readAsDataURL(image) 


ここでは、むメヌゞをダりンロヌドしお凊理するために、を通じおリモヌトメ゜ッドを実行しMeteor.callたす。ご芧のずおり、クラむアントでリモヌトプロシヌゞャを呌び出すこずは、通垞の関数呌び出しずそれほど倉わらず、匕数で枡されるすべおのデヌタはWeb゜ケットを介しおサヌバヌにダりンロヌドされたす。ナヌザヌファむルを読み取るために、HTML5仕様のFile APIを䜿甚したした。

画像をロヌドする䟋は、最も成功するずは限りたせんが、流星のサヌバヌ偎の機胜をよく瀺しおいたす。本番甚に䜜成しおいる堎合は、既補のCollectionFS゜リュヌションを䜿甚できたす。

new_board


原則ずしお、このレッスンでカバヌしたかったのはこれだけですが、完党を期すために、ボヌドのカヌドの機胜を終了したす。このレッスンにないものは䜿甚したせん。リポゞトリで通垞どおり倉曎を確認できたす。

tasks



参照資料

Source: https://habr.com/ru/post/J242943/


All Articles