Rails4でRiot.js(3.3)が動く環境を構築する
実行環境
Ruby on Rails 4.2.0
Riot.js 3.3.2
前提
あらかじめNode.jsがローカルにインストールされていること。
$ node -v
を実行してバージョンが表示されればOK。
1. npmを使ってriotをインストールする
$ cd (Railsプロジェクト直下のディレクトリ)
プロジェクト直下にpackage.jsonがない場合は下記を実行
$ npm init
=> 基本Entで進み、package.jsonが作成される
packeage.jsonを編集
scripts, devDependenciesの箇所にriotを記載。
今回riotのバージョンを指定したが、しなくてもOK。編集が終わったら保存。
{ "name": "(プロジェクト名)", "version": "1.0.0", "description": "", "scripts": { "riot": "riot" }, "devDependencies": { "riot": "3.3.2" }, "private": true }
フロントエンド系のソースをまとめたいのでプロジェクト直下にディレクトリを作成
$ mkdir ./frontend
package.jsonを/frontend
以下へ移動する
$ mv ./package.json frontend/
npmを使ってriotをインストール。
今回このプロジェクトのみにインストールしたかったのでgオプションはつけませんでした。 また、指定のディレクトリ以下にインストールしたかったのでprefixオプションをつけました。
$ npm install --prefix ./frontend/
frontend以下にetc, node_modulesディレクトリが作成された!
この時点でfrontend以下はこのようなディレクトリ構造になっていると思います。
frontend/ ├── etc ├── node_modules ├── package.json └── riot ├── sample.tag
2. RailsでRiot.jsを使うためにソースをDLしてきて配置する
gemもあるようだけど、うまく動かなかったのでRiotの公式サイトからソースファイルをDLしてきて利用することにした。
curlコマンドでcompilerが含まれたmin.jsファイルをDLしてくる。
公式サイトのGitHubから、riot+compiler.min.jsを取得する。RawボタンからリンクするページのURLを指定すること〜。
oオプションをつけるとこの名前で保存するという指定ができる。 (↓改行されているけどワンライナーです)
$ curl https://raw.githubusercontent.com/riot/riot/master/riot%2Bcompiler.min.js -o ./vendor/assets/javascripts/riot.js
application.jsに追記し、上記のソースが読み込まれるようにする。
app/assets/javascripts/application.js
(省略) //= require riot
これで環境構築は完了!
3. サンプルファイルを配置し、コンパイルを実行
tagファイルを作成
$ mkdir frontend/riot
$ touch frontend/riot/sample.tag
公式サイトで配布されているサンプルコードをコピーし、sample.tagとして保存
<sample> <h3>{ message }</h3> <ul> <li each={ techs }>{ name }</li> </ul> <script> this.message = 'Hello, Riot!' this.techs = [ { name: 'HTML' }, { name: 'JavaScript' }, { name: 'CSS' } ] </script> <style> :scope { font-size: 2rem } h3 { color: #444 } ul { color: #999 } </style> </sample>
html.erbファイルを作成
ブラウザで確認出来るviewファイルのbodyタグ内にsampleタグを配置し、mountする処理を書く。
(例)app/views/articles/index.html.erb
<!-- place the custom tag anywhere inside the body --> <sample></sample> <!-- mount the tag --> <script>riot.mount('sample')</script>
コンパイルを実行し、tagファイルからjsファイルを作成
$ ./frontend/node_modules/.bin/riot ./frontend/riot/ app/assets/javascripts/riot/
↑については下記のような意味
[npm内のriotファイル] [tagファイルがあるディレクトリを指定] [jsファイルを作成したいディレクトリを指定]
4. 実行
ブラウザで上記のhtml.erbファイルを確認すると、、
Riotのコードが正しく実行されている(このサンプルの場合はsample.tagで設定した内容が表示されている)ことが確認出来る!
5. 諸々コミット対象から外しておく
node_modules以下、tagファイルはコミット対象に入れない方がベターなので、.gitignoreに追記しておく。
.gitignore
(省略) /frontend/node_modules/* /app/assets/javascripts/riot/*
Rails4以降でJSONデータを作る時にはjbuilderがお便利
jbuilderというjsonのテンプレートエンジンを使うと、viewディレクトリ以下にxxx.json.jbuilderファイルを作成し、localhost:3000/xxx.jsonとアクセスするだけでJSON形式のレスポンスを受け取ることができる。
app/views/api/index.json.jbuilder(今回はapiというnamespaceを切っている)
json.prefectures @prefectures do |prefecture| //コントローラー側でDBのデータを取得する@prefecturesを生成している json.id prefecture.id json.name prefecture.name end
コントローラーをはさまなくでも直接モデルを参照する書き方ももちろんOK!
json.prefectures Prefecture.all do |prefecture| json.id prefecture.id json.name prefecture.name end
app/controllers/api/prefectures_controller.rb
class Api::PrefecturesController < Api::ApplicationController def index @prefectures = Prefecture.all end end
これで http://localhost:3000/api/prefectures.json
にアクセスすると下記のようなデータが取得できる
{"prefectures":[{"id":1,"name":"東京都"},{"id":2,"name":"埼玉県"},{"id":3,"name":"千葉県"}]}
また、アクセスするURLをjson形式にあらかじめ限定しておくとhttp://localhost:3000/api/prefectures
でアクセス可能
config/routes.rb
Rails.application.routes.draw do 中略 namespace :api, { format: 'json' } do resources :prefectures, only: [:index, :show] end end
コントローラーのindexアクション内で render :json => オブジェクト
とする場合もJSON形式のデータを取得できるが、jbuilderを使う場合がより便利なのは、、
- updated_atだけで良いのでcreated_atはJSONの項目から消して欲しいなど、出力するカラムの選択ができる
- 特定の条件の時だけ表示形式を変えたい(日付表示に関して割りとよくある要望)
- キャッシュしておく仕組みが無い
ということでとても融通が利きそう!
参照元記事:
子テーブルのレコード件数を取る際に使える!counter_culture
投稿に対するコメント数などを取る際に、複雑なSQLを書こうとしていたのですが、 counter cache(カウンターキャッシュ)というものを使えばとてもスマートに各投稿へのコメント数が取得できました。
さすがRails、痒いところに手が届きます!
投稿数が多くなることを考えて、今回はcounter_cultureというgemを使うことにしました。
下記のような親子関係のテーブル(1対多)
親:Question, 子:Answer
ステップは下記
gemを追加
親テーブルにカウント数格納用のカラムを追加
子のモデルにcounter_cultureの記述を追記
1. gemを追加
gem 'counter_culture'
2. 親テーブルにカウント数格納用のカラムを追加
ジェネレーターを使う場合
$ rails generate counter_culture Question answers_count
Migrationファイルを使い、下記のようなカラム追加でもいけます
add_column :questions, :answers_count, :integer, null: false, default: 0
3. 子モデルにcounter_cultureの記述を追加
app/models/questions.rb
class Question < ApplicationRecord has_many :answers end
app/models/answers.rb
class Answer < ApplicationRecord belongs_to :question counter_culture :question, column_name: 'answers_count' #任意のカラム名を付ける場合のみcolumn_nameが必要 end
Viewでは他の値と同様に下記のように呼び出せます。
<% @questions.each do |question| %> <%= question.title %> <%= question.answers_count %> <% end %>
LEFT OUTER JOINとGROUP BYを使ったSQLを書くのに苦労していたのでとても助かりましたε-(´∀`*)ホッ
参照元:
Rails5 マイグレーションファイルでのindexの書き方が変わった
add_index
で書いていた箇所がカラム追加と同じメソッド内にt.index
という形で書けるようになったみたいです。
Class CreateQuestions < ActiveRecord::Migration[5.0] def change create_table :questions do |t| t.string :title t.text :content t.index :title, unique: true #こんな感じ end end end
元の書き方でも動きますが、すっきり!
Rails 5でアプリ作成してみた
installする際に少しハマりましたが、基本はRails4系と変わらなかったのです。
1. Rubyのバージョンを最新にする
Rails5ではRuby 2.2.2
以降が必須らしい。
ローカルのworkingディレクトリに移動し、Rubyのバージョンを確認
$ ruby -v
2.3.0だったので、アップデートは不要。
ちなみに最新版を確認するコマンドは下記
$ rbenv install --list
2. Railsのバージョンを最新にする
現在のバージョンは4.2.5
だったので、最新版5.0.0をインストール!
$ gem install rails --pre
--pre
オプションで最新版を指定できるらしい
エラー発生 (ノω・、)
nio4r
というものをinstallする箇所でコケている!
logファイルを確認
$ cat /Users/kaorina/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/extensions/x86_64-darwin-13/2.3.0-static/nio4r-1.2.1/mkmf.l
og
xcodeのiosをゴニョゴニョするというメッセージが出ていただので(スクリーンショット取り損ねました。。)
xcodeを立ち上げて、ステップに沿ってアップデート。
そして、再度installコマンドを実行したらイケた!
以下のステップはRailsのバージョン問わず同じです。
scaffoldコマンドでサクッとアプリを作成
newコマンドでアプリの土台を作成。(DBはPosgreを指定)
$ rails _5.0.0.1_ new threedprinterq -d postgresql
アプリのフォルダに移動しbundle install
今回のアプリ名は threedprinterqというQ&Aアプリを作ります
$ cd threedprinterq
$ bundle install
config/application.rbを編集
require_relative 'boot' require 'rails/all' Bundler.require(*Rails.groups) module Threedprinterq class Application < Rails::Application config.time_zone = 'Tokyo' #config.i18n.default_locale = :ja #日本語使う指定は後で有効にする config.active_record.default_timezone = :local config.autoload_paths += %W(#{config.root}/lib) #lib以下を読み込むように設定 config.generators do |g| g.test_framework :rspec, #テストはrspecを使用。コントローラーのテストのみ自動作成 fixtures: true, view_specs: false, helper_specs: false, routing_specs: false, controller_specs: true, request_specs: false g.fixture_replacement :factory_girl, dir: "spec/factories" #factory_girlを使用 g.assets false g.helper false end end end
Rails4では下記も記載していましたが、5ではコールバックの処理方法が変わったのでいらないのかなーと思っています。
config.active_record.raise_in_transactional_callbacks = true
参照:
Rails アップグレードガイド | Rails ガイド
posgreを起動
$ postgres -D /usr/local/var/postgres
DBを作成
$ bundle exec rake db:create
質問用のCRUDを作成
カラムはtitile, とtext型のcontentという構成
$ rails g scaffold question title content:text
Migration実行
$ bundle exec rake db:migrate
ブラウザで確認
$ rails s
を実行後、ブラウザで http://localhost:3000/ にアクセスすると
素敵なwelcomeページが出てきた!わーい!
qiitamarkdownのプレビュー画面をboorstrapのモーダルウィンドウで表示する
Q&Aサイト等で投稿内容をMarkdown形式で書いて、投稿前に確認出来るプレビューWindowを作りました。 Bootstrap3でモーダルウィンドウというものがあるので簡単にいい感じのWindowが使えました。
Markdown形式をHTML形式に変換してくれるライブラリqiitamarkdownについてはこちら
GitHub - increments/qiita-markdown: Qiita-specified markdown processor.
イメージ
内容欄に記述後、プレビューボタンを押すとwindowがプレビュー画面が確認できます。
方法はこちら
previewページ用のルーティングを追加
今回、質問投稿用の画面(questions)以下に実装する
config/routes.rb
resources :questions do post :preview, on: :collection end
controllerにpreviewアクションを追加
app/views/controllers/questions_controller.rb
def preview markdown = qiita_markdown(params[:text]) render text: markdown end private def qiita_markdown(markdown) processor = Qiita::Markdown::Processor.new processor.call(markdown)[:output].to_s.html_safe end
viewの編集
app/views/questions/new.html.erb
app/views/questions/edit.html.erb
ともに同じパーシャルを呼び出し
<%= render 'form' %>
app/views/questions/_form.html.erb
<%= form_for(@question) do |f| %> --- 中略 --- <div> <%= f.text_field :title, class: "form-control", placeholder: "タイトル" %> </div> <div> <%= f.text_area :body, class: "form-control", placeholder: "内容", row: 10, required: 'required' %> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal" id="preview_button">内容欄プレビュー</button> </div> <%= render 'preview_window' %>
モーダルウィンドウ用のviewを作成
app/views/questions/_preview_window.html.erb
<div class="modal fade" id="myModal"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title">内容プレビュー</h4> </div> <div class="modal-result" id="modal-result"> </div> </div> </div> </div>
previewボタンが押下された時に発火するAjaxを作成
app/assets/javascripts/preview.coffee
$ -> update_preview = (text) -> $.ajax url: '/questions/preview' type: 'POST' data: {text: text} success: (data) -> $('#modal-result').html(data) return error: (xhr, status, err) -> $('#modal-result').html 'エラーが発生しました ' + err return $('#preview_button').click -> update_preview($('#question_body').val()) return
下記を参考にさせていただきたました。
こちらはプレビューWindowでなく、同じページ内にライブプレビューを実装されています。
ありがとうございました :)
GitHub - katoy/qiita_markdown_example: makedown のライブプレビューのサンプル
railsの変数をjavascript内で使えるgonが便利だよ
asset配下のjavascript内でrailsの変数を使いたい場合、 gonというGemを使えばすぐに呼び出せます。
Gemをインストール
Gemfile
に下記を追記後、bundle install
を実行
gem 'gon'
application.html.erbへ設定を追記
app/views/layouts/admin/application.html.erb
<head>
タグ内に設定の一筆を書く
<%= include_gon %>
controller内に変数を書く
app/controllers/hoges_controller.rb
def hohohoho gon.user_name = "Kaorina" #ユーザー名Kaorinaをgon.xxxという変数名に入れる end
javascript側から変数を参照!
app/assets/javascripts/hoge.js
$(document).ready(function() { var userName = gon.user_name #コントローラーで設定した変数名 gon.xxxでよびだせる });
配列、ハッシュも渡すことができるようです。
gon.name = ["Kaorina", "Suzukina"]
gon.name = { first: "Kaorina", last: "Suzukina"}