完成したアプリケーションの例。
Oxymoronはどのようなタスクを解決しますか?
私にとって、このgemはルーチンコードの量を1桁削減し、その結果、開発速度を大幅に向上させます。 これにより、AngularJSとRoRの相互運用性を非常に簡単に構築できます。
- routes.rbに基づいて、AngularJSルーティングを自動的に構築する
- routes.rbからAngularJSリソースを自動生成
- AngularJSコントローラーのアーキテクチャの厳密な設定
- 常に使用される構成の処方
- フォーム検証
- FormBuilderが自動的にngモデルを付加する
- 通知
- 一般的に使用されるディレクティブ(ajax fileupload、click-outside、content-for、check-list)
- JsRoutesのコンパクトなアナログの実装
どのように機能しますか?
まず、gemをGemfileに接続する必要があります。
gem 'oxymoron'
これで、 routes.rbを変更するたびに 、またはアプリケーションを再起動するたびに、アプリケーションを構築するために必要なすべてのコードを含むoxymoron.jsファイルがapp / asset / javascriptsに生成されます。
次のステップは、アセットを構成することです。 最も単純な場合、次のようになります。
application.jsの場合:
/* = require oxymoron/underscore = require oxymoron/angular = require oxymoron/angular-resource = require oxymoron/angular-cookies = require oxymoron/angular-ui-router = require oxymoron/ng-notify = require oxymoron = require_self = require_tree ./controllers */
application.cssの場合:
/* *= require oxymoron/ng-notify *= require_self */
UIルーターを使用するため、レイアウトでui-viewタグを定義する必要があります。 アプリケーションはHTML5ルーティングを使用するため、ベースタグを指定する必要があります。 私たちの場合、これはapplication.html.slimです。 私はSLIMをプリプロセッサとして使用し、すべての人に強くアドバイスします。
html ng-app="app" head title base href="/" = stylesheet_link_tag 'application' body ui-view = javascript_include_tag 'application'
すべてのAJAXリクエストについて、レイアウトをオフにする必要があります。 これを行うには、ApplicationControllerに必要なロジックを記述します。
layout proc { if request.xhr? false else "application" end }
フォームの正しい処理とng-modelのインストールのために、デフォルトのFormBuilderをOxymoronFormBuilderにオーバーライドする初期化子を作成する必要があります。
ActionView::Base.default_form_builder = OxymoronFormBuilder
最後に行う必要があるのは、アプリケーションにoxymoronモジュールを挿入し、自動生成されたルーティングが使用されることをUIルーターに伝えることです。
var app = angular.module("app", ['ui.router', 'oxymoron']); app.config(['$stateProvider', function ($stateProvider) { $stateProvider.rails() }])
すべてが本格的なSPAアプリケーションを作成する準備ができました!
最も簡単なSPAブログを書きましょう
だから。 最初に、このモデルを管理するためのPostモデルとRESTfulコントローラーを準備します。 これを行うには、コンソールで次のコマンドを実行します。
rails g model post title:string description:text rake db:migrate rails g controller posts index show
routes.rbで、postsリソースを作成します。
Rails.application.routes.draw do root to: "posts#index" resources :posts end
次に、コントローラーのメソッドについて説明します。 多くの場合、同じメソッドが応答でJSON構造とHTMLマークアップの両方を返すことがあるため、そのようなメソッドはrespond_toでラップする必要があります。
典型的なRailsコントローラーの例
class PostsController < ActiveRecord::Base before_action :set_post, only: [:show, :edit, :update, :destroy] def index respond_to do |format| format.html format.json { @posts = Post.all render json: @posts } end end def show respond_to do |format| format.html format.json { render json: @post } end end def new respond_to do |format| format.html format.json { render json: Post.new } end end def edit respond_to do |format| format.html format.json { render json: @post } end end def create @post = Post.new post_params if @post.save render json: {post: @post, msg: "Post successfully created", redirect_to: "posts_path"} else render json: {errors: @post.errors, msg: @post.errors.full_messages.join(', ')}, status: 422 end end def update if @post.update(post_params) render json: {post: @post, msg: "Post successfully updated", redirect_to: "posts_path"} else render json: {errors: @post.errors, msg: @post.errors.full_messages.join(', ')}, status: 422 end end def destroy @post.destroy render json: {msg: "Post successfully deleted"} end private def set_post @post = Post.find(params[:id]) end def post_params params.require(:post).permit(:title, :description) end end
各Railsコントローラーには、AngularJSコントローラーがあります。 マッチングルールは非常に簡単です。
PostsController => PostsCtrl Admin::PostsController => AdminPostsCtrl # namespace Admin
app / javascripts / controllers / post_ctrl.jsに適切なコントローラーを作成します。
典型的なAngularJSコントローラーの例
app.controller('PostsCtrl', ['Post', 'action', function (Post, action) { var ctrl = this; // '/posts' action('index', function(){ ctrl.posts = Post.query(); }); // '/posts/:id' action('show', function (params){ ctrl.post = Post.get({id: params.id}); }); // '/posts/new' action('new', function(){ ctrl.post = Post.new(); // , . . . ctrl.save = Post.create; }); // '/posts/:id/edit' action('edit', function (params){ ctrl.post = Post.edit({id: params.id}); // ctrl.save = Post.update; }) // . edit new. action(['edit', 'new'], function(){ // }) action(['index', 'edit', 'show'], function () { ctrl.destroy = function (post) { Post.destroy({id: post.id}, function () { ctrl.posts = _.select(ctrl.posts, function (_post) { return _post.id != post.id }) }) } }) // routes.rb . : '/posts/some_method' action('some_method', function(){ // }) // etc }])
工場出荷時の措置に注意してください。 これを使用すると、アプリケーションのページ間でコードを分割するのに非常に便利です。 ファクトリーは、oxymoron.jsで生成された状態を介して解決し、その結果、コントローラーの現在のrailメソッドを認識します。
action(['edit', 'new'], function(){ // posts/new posts/:id/edit })
次に、 ポストファクトリに注意してください。 このファクトリは、routes.rbで定義されたリソースから自動的に生成されます。 適切に生成するには、リソースでshowメソッドを定義する必要があります。 次のリソースの操作方法は、ボックスから利用できます。
Post.query() // => GET /posts.json Post.get({id: id}) // => GET /posts/:id.json Post.new() // => GET /posts/new.json Post.edit({id: id}) // => GET /posts/:id/edit.json Post.create({post: post}) // => POST /posts.json Post.update({id: id, post: post}) // => PUT /posts/:id.json Post.destroy({id: id}) // => DELETE /posts/:id.json
カスタムリソースメソッド(メンバーとコレクション)はまったく同じように機能します。 例:
resources :posts do member do get "comments", is_array: true end end
AngularJSリソースに適切なメソッドを作成します。
Post.comments({id: id}) //=> posts#comments
応答で配列が予期されることが予想される場合は、 is_array:trueオプションを設定します。 そうでない場合、AngularJSは例外をスローします。
不足しているビューを作成するために残ります。
投稿/ index.html.slim
h1 Posts input.form-control type="text" ng-model="search" placeholder="" br table.table.table-bordered thead tr th Date th Title th tbody tr ng-repeat="post in ctrl.posts | filter:search" td ng-bind="post.created_at | date:'dd.MM.yyyy'" td a ui-sref="post_path(post)" ng-bind="post.title" td.w1 a.btn.btn-danger ng-click="ctrl.destroy(post)" a.btn.btn-primary ui-sref="edit_post_path(post)"
投稿/ show.html.slim
.small ng-bind="ctrl.post.created_at | date:'dd.MM.yyyy'" a.btn.btn-primary ui-sref="edit_post_path(ctrl.post)" a.btn.btn-danger ng-click="ctrl.destroy(ctrl.post)" h1 ng-bind="ctrl.post.title" p ng-bind="ctrl.post.description"
投稿/ new.html.slim
h1 New post = render 'form'
投稿/ edit.html.slim
h1 Edit post = render 'form'
投稿/ _form.html.slim
= form_for Post.new do |f| div = f.label :title = f.text_field :title div = f.label :description = f.text_area :description = f.submit "Save"
form_forヘルパーの生成結果に特に注意を払う必要があります。
<form ng-submit="formQuery = ctrl.save({form_name: 'post', id: ctrl.post.id, post: ctrl.post}); $event.preventDefault();"></form>
コントローラー内でctrl.saveメソッドを定義するだけで十分です。フォームを送信して表示されるパラメーターを渡すたびに実行されます。 ただし、これらのパラメーターはリソースメソッドの更新および作成の引数として理想的であるため、コントローラーではctrl.save = Post.createのみを記述できます。 PostsCtrlリストでは、このポイントには対応するコメントが付けられています。
ng-model属性は、 text_fieldおよびtext_areaタグに対して自動的に追加されました。 ng-modelコンパイルルールは次のとおりです。
ng-model="ctrl._._"
JSON機能のレンダリング:{}
PostsControllerのレールリストで、おそらくrenderメソッドのmsg、redirect_toなどのフィールドに気付いたでしょう。 これらのフィールドには特別なインターセプターが機能し、結果がコントローラーに送信される前に必要なアクションを実行します。
msg-画面上部の緑色のポップアップに内容が表示されます。 エラーのステータスをレンダリングに渡すと、色が赤に変わります
errors-エラーオブジェクトを受け取り、フォームフィールド自体にエラーを直接表示するのに役立ちます。
redirect_to-必要なUIルーター状態にリダイレクトします
redirect_to_options-状態にオプションが必要な場合、たとえば、show pageにはidが必要な場合、このフィールドでそれらを指定する必要があります
redirect_to_url-指定されたURLにジャンプします
reload-ページをユーザーに完全にリロードします
これらすべてのアクションは、ユーザーページをリロードすることなく実行されます。 UIルーターに基づくHTML5ルーティングを使用します。
今link_toなし
以前は、ルートの名前に応じてリンクを定義する場合、 link_toヘルパーを使用する必要がありました。 現在、この機能はルートを記述する通常の方法でui-srefによって実装されています。
a ui-sref="posts_path" a ui-sref="post_path({id: 2})" №2 a ui-sref="edit_post_path({id: 2})" №2 a ui-sref="new_post_path"
js-routesの軽量アナログ。 対立
グローバルスコープでは、Routes変数を見つけることができます。 js-routesとほぼ同じように機能します。 唯一の違いは、この実装はオブジェクトのみを受け入れ、数値引数として砂糖を持たないことです。 競合がある可能性があるため、js-routesを無効にすることをお勧めします。
Routes.posts_path() // => "/posts" Routes.new_post_path() // => "/post/new" Routes.edit_posts_path({id: 1}) // => "/post/1/edit" // Routes.defaultParams = {id: 1} Routes.post_path({format: 'json'}) // => "/posts/1.json"
まとめ
プリミティブなSPAアプリケーションを作成しました。 同時に、コードは完全にレールに見え、ロジックは最小限に記述されており、すでに最も一般的なものです。 完璧に制限はなく、Oxymoronは理想からほど遠いことを理解していますが、私のアプローチに誰かに興味を持てたことを望みます。 私は宝石の人生に対する批判と積極的な参加に喜んでいます。
完成したアプリケーションの例。