Rails入門(チュートリアル)

ruby on rails の勉強がてら、本家のチュートリアルを一通り実行してみる

3.2 プロジェクトの作成
$ rails new blog
- ヘルプが見れる(rails new -h)

3.3.1 DBの内容
config/database.yml
- 各環境の設定内容が記述されている
- デフォルトではsqlite3

3.4 DBの生成
$ rake db:create

4.1 サーバ起動
$ rails server
- http://localhost:3000 にアクセスするとwelcomeページが表示される
- 終了はCtrl+c

4.2 お決まりのHello world
- コントローラの生成
$ rails generate controller home index
- 生成されるコントローラは app/controllers/home_controller.rb
- view(html)を修正app/views/home/index.html.erb
<h1>Hello, Rails!</h1>

4.3 アプリケーションのHomeページを設定
- 必ずpublic/index.html が表示されてしまうため削除
$ rm public/index.html
- ディスパッチの設定を追加
- ファイル: config/routes.rb

Blog::Application.routes.draw do
#...
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
root :to => "home#index"

- その後再度 http://localhost:3000 にアクセスすると、先ほどのテンプレートが表示される

6 リソースの作成(MVCを作る)
- scaffold を指定すると、model, view, controllerを一括で作成してくれる
$ rails generate scaffold Post name:string title:string content:text

6.1 マイグレーション
- テーブルの作成や、変更などを管理する仕組み
- ファイル :db/migrate/20120508162203_create_posts.rb
- マイグレーションスクリプト実行
$ rake db:migrate
- productionで作成する場合はオプションをつける rake db:migrate RAILS_ENV=production

6.2 Topページにリンクを追加
- ファイル : app/views/home/index.html.erb
<h1>Hello, Rails!</h1>
<%= link_to "My Blog", posts_path %>

- link_to [タイトル], 遷移先?

6.4 モデルの確認
- ファイル : app/models/post.rb

6.5 バリデータの追加
- ファイル : app/models/post.rb
class Post < ActiveRecord::Base
attr_accessible :content, :name, :title
validates :name, :presence => true
validates :title, :presence => true,
:length => { :minimum => 5 }
end

- attr_accessibleは変更可能なパラメータ
- presence は必須、lengthは長さを指定

6.6 コンソールを使ってみよう
$ rails console
>> p = Post.new(:content => "A new post")
=> #<Post id: nil, name: nil, title: nil,
content: "A new post", created_at: nil,
updated_at: nil>
>> p.save
=> false
>> p.errors.full_messages
=> ["Name can't be blank", "Title can't be blank", "Title is too short (minimum is 5 characters)"]

- バリデータが効いているのがわかる

6.7 一覧ページ
- ファイル : app/controllers/posts_controller.rb
def index
@posts = Post.all

respond_to do |format|
format.html # index.html.erb
format.json { render json: @posts }
end
end

- @postsに投稿内容をすべて取得する
- html, jsonに対応
- http://localhost:3000/posts.html
- http://localhost:3000/posts.json

- テンプレート : app/views/posts/index.html.erb
- html エスケープしない場合、
- rails 2 だと <%=h post.name %>
- rails 3 では <%= raw post.name %>

6.8 カスタムレイアウト
- フッターやヘッダーを定義
- ファイル : app/views/layouts/application.html.erb
- 各コントローラ毎に指定する場合
- app/views/layouts/posts.html.erb

6.9 新規作成ページ
- ファイル : app/controllers/posts_controller.rb
def new
@post = Post.new

respond_to do |format|
format.html # new.html.erb
format.json { render json: @post }
end
end
- テンプレート : app/views/posts/new.html.erb
<h1>New post</h1>
<%= render 'form' %>
<%= link_to 'Back', posts_path %>
- render 'form'を指定することで、app/views/posts/_form.html.erb の内容を出力する

- 投稿処理
def create
@post = Post.new(params[:post])

respond_to do |format|
if @post.save
format.html { redirect_to @post, notice: 'Post was successfully created.' }
format.json { render json: @post, status: :created, location: @post }
else
format.html { render action: "new" }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end

6.10 詳細表示
- http://localhost:3000/posts/1 にアクセスすると /posts/(id) として、:idに取得可能
def show
@post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => @post }
end
end

- テンプレート : app/views/posts/show.html.erb

6.11 編集ページ
- 詳細表示と違い、jsonでのレスポンスがないためシンプル
def edit
@post = Post.find(params[:id])
end
- 更新処理
def update
@post = Post.find(params[:id])

respond_to do |format|
if @post.update_attributes(params[:post])
format.html { redirect_to @post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
- update_attributesで必要なパラメータを更新

6.12 削除
- ファイル : app/controllers/posts_controller.rb
def destroy
@post = Post.find(params[:id])
@post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.json { head :no_content }
end
end

7.1 モデルの追加
- テーブル間のリレーションシップを指定 post:references
$ rails generate model Comment commenter:string body:text post:references
- モデルクラスにも定義されている
- ファイル : app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :post
attr_accessible :body, :commenter
end

- 再度マイグレーションスクリプトが生成されているて、それを反映
- ファイル : db/migrate/20120508170658_create_comments.rb
$ rake db:migrate

7.2 関連づけモデル
- 1投稿に付き複数のコメントが存在するためPostのmodelを修正
- ファイル :app/models/post.rb
class Post < ActiveRecord::Base
attr_accessible :content, :name, :title
validates :name, :presence => true
validates :title, :presence => true,
:length => { :minimum => 5 }
has_many :comments
end

7.3 ルート(ディスパッチ)にコメントを追加
- ファイル : config/routes.rb
- posts部分を修正
resources :posts do
resources :comments
end

7.4 コントローラの追加
$ rails generate controller Comments
- 上記エラー出る場合、ルートファイルで追加した部分をコメントアウトする

- Postのテンプレートにcomment投稿を追加
- ファイル : app/views/posts/show.html.erb
<p id="notice"><%= notice %></p>

<p>
<b>Name:</b>
<%= @post.name %>
</p>

<p>
<b>Title:</b>
<%= @post.title %>
</p>

<p>
<b>Content:</b>
<%= @post.content %>
</p>

<h2>Add a comment:</h2>
<%= form_for([@post, @post.comments.build]) do |f| %>
<div class="field">
<%= f.label :commenter %><br />
<%= f.text_field :commenter %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

<%= link_to 'Edit', edit_post_path(@post) %> |
<%= link_to 'Back', posts_path %>

- コメントコントローラに処理を追記
- ファイル : app/controllers/comments_controller.rb
def create
@post = Post.find(params[:post_id])
@comment = @post.comments.create(params[:comment])
redirect_to post_path(@post)
end


- 詳細画面でコメントを閲覧できるように修正
- ファイル : app/views/posts/show.html.erb
<h2>Comments</h2>
<% @post.comments.each do |comment| %>
<p>
<b>Commenter:</b>
<%= comment.commenter %>
</p>
<p>
<b>Comment:</b>
<%= comment.body %>
</p>
<% end %>


8.リファクタリング
- テンプレートの共通部分を外だししてみる

8.1 コレクション
- コメント部分のテンプレを外だし
- ファイル : app/views/comments/_comment.html.erb
<p>
<b>Commenter:</b>
<%= comment.commenter %>
</p>
<p>
<b>Comment:</b>
<%= comment.body %>
</p>

- 参照部分の修正 app/views/posts/show.html.erbを修正 (まだ納得は行かない><)
- 修正前
<% @post.comments.each do |comment| %>
<p>
<b>Commenter:</b>
<%= comment.commenter %>
</p>
<p>
<b>Comment:</b>
<%= comment.body %>
</p>
<% end %>

- 修正後
<%= render @post.comments %>

8.2 Form部分の外だし
- ファイル : app/views/comments/_form.html.erb
<%= form_for([@post, @post.comments.build]) do |f| %>
<div class="field">
<%= f.label :commenter %><br />
<%= f.text_field :commenter %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

- 参照部分の修正 : app/views/posts/show.html.erb
- 今回は単純に置き換える
<%= render "comments/form" %>

9 コメントの削除
- リンクの追加 : app/views/comments/_comment.html.erb
<p>
<%= link_to 'Destroy Comment', [comment.post, comment],
:confirm => 'Are you sure?',
:method => :delete %>
</p>

- コントローラに追加 : app/controllers/comments_controller.rb
def destroy
@post = Post.find(params[:post_id])
@comment = @post.comments.find(params[:id])
@comment.destroy
redirect_to post_path(@post)
end

9.1 関連データの削除も対応
- 親の投稿データが削除された場合、一緒に削除
- ファイル : app/models/post.rb
class Post < ActiveRecord::Base
attr_accessible :content, :name, :title
validates :name, :presence => true
validates :title, :presence => true,
:length => { :minimum => 5 }
has_many :comments, :dependent => :destroy
end

10 セキュリティー
- Basic認証
- ファイル : app/controllers/posts_controller.rb
class PostsController < ApplicationController
http_basic_authenticate_with :name => "dhh", :password => "secret", :except => [:index, :show]
# GET /posts
# GET /posts.json
def index
@posts = Post.all

- :exceptで対象外を指定
- :only => :destroy を指定すると、削除のみ認証する

11 複数モデル
- タグモデルの生成
$ rails generate model tag name:string post:references
- マイグレーション実行
$ rake db:migrate
- モデルに関連づけを行う
- ファイル : app/models/post.rb
has_many :tag

accepts_nested_attributes_for :tags, :allow_destroy => :true,
:reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }

- accepts_nested_attributes_forは親子関係の定義?
- allow_destroyはネストした属性にチェックボックスを表示
- reject_if は禁止条件を設定

- フォームテンプレートにタグを追加
- ファイル : views/posts/_form.html.erb
<h2>Tags</h2>
<%= render :partial => 'tags/form',
:locals => {:form => post_form} %>

- タグ用のフォームテンプレート
- ファイル : app/views/tags/_form.html.erb
<%= form.fields_for :tags do |tag_form| %>
<div class="field">
<%= tag_form.label :name, 'Tag:' %>
<%= tag_form.text_field :name %>
</div>
<% unless tag_form.object.nil? || tag_form.object.new_record? %>
<div class="field">
<%= tag_form.label :_destroy, 'Remove:' %>
<%= tag_form.check_box :_destroy %>
</div>
<% end %>
<% end %>

- 投稿テンプレートにタグを追加
- ファイル : app/views/posts/show.html.erb
<p>
<b>Tags:</b>
<%= @post.tags.map { |t| t.name }.join(", ") %>
</p>

12 View Helpers
- ファイル : app/helpers/posts_helper.rb
def join_tags(post)
post.tags.map { |t| t.name }.join(", ")
end

- 使ってみる : app/views/posts/show.html.erb
- 変更前
<p>
<b>Tags:</b>
<%= @post.tags.map { |t| t.name }.join(", ") %>
</p>
- 変更後
<p>
<b>Tags:</b>
<%= join_tags(@post) %>
</p>

0 件のコメント:

コメントを投稿

ReactNativeでAndroid対応する話

前提 ReactNativeでiOS版のアプリをリリースしていて、Android版をリリースする話 トラブルシューティング Build.VERSION_CODES.Q が存在しないエラー compileSdkVersionを29以上にすると解決 メモリー足りないエラー Execu...