Railsで作るログイン可能なブログシステム

Railsを説明したり自分で試してみるときにいつも作っているなぁと思ったのでマスターを作ってみました。エンジニアでブログを知らない人はいないので説明するとき便利なんですよね。


誰かの役に立つかも知れないので作業ログを公開します。

システム要件

  • gitがインストールされていること
  • sqlite3がインストールされていること
  • Rails > 2.2

環境がない人はぜひUbuntuを使って環境構築しましょう!→Rails開発環境をUbuntu8.04に構築するメモ - koumiyaの日記

プロジェクト作成からDB作成まで

$ rails blog
$ cd blog
$ script/plugin install git://github.com/technoweenie/restful-authentication.git
$ script/generate authenticated user
$ script/generate scaffold blog title:string user:belongs_to
$ script/generate scaffold entry title:string body:text blog:belongs_to
$ rake db:migrate

変更のポイント

scaffoldで土台はできたのであとは生成されたファイルを変更するだけです。ポイントは、

  • ルーティングにはRails 2.2のshallowオプションを使います。
  • ブログとエントリーのコントローラはログインを必須にします。
  • scaffoldのままではModel同士が関係を持っていないので、ログイン中のユーザーのブログ、選択したブログのエントリーという関係を持たせます。

変更

変更箇所のdiffを貼っておきます。

app/config/routes.rb
@@ -1,7 +1,7 @@
 ActionController::Routing::Routes.draw do |map|
-  map.resources :entries
-
-  map.resources :blogs
+  map.resources :blogs, :shallow => true do |blog|
+    blog.resources :entries
+  end
 
   map.logout '/logout', :controller => 'sessions', :action => 'destroy'
   map.login '/login', :controller => 'sessions', :action => 'new'
app/controllers/application.rb
@@ -2,11 +2,12 @@
 # Likewise, all the methods added will be available for all controllers.
 
 class ApplicationController < ActionController::Base
+  include AuthenticatedSystem
   helper :all # include all helpers, all the time
app/controllers/blogs_controller.rb
@@ -1,8 +1,10 @@
 class BlogsController < ApplicationController
+  before_filter :login_required
+
   # GET /blogs
   # GET /blogs.xml
   def index
-    @blogs = Blog.find(:all)
+    @blogs = current_user.blogs
 
     respond_to do |format|
       format.html # index.html.erb
@@ -40,7 +42,7 @@
   # POST /blogs
   # POST /blogs.xml
   def create
-    @blog = Blog.new(params[:blog])
+    @blog = current_user.blogs.build(params[:blog])
 
     respond_to do |format|
       if @blog.save
app/controllers/entries_controller.rb
@@ -1,9 +1,10 @@
 class EntriesController < ApplicationController
+  before_filter :login_required
+  before_filter :load_blog, :only => [:index, :new, :create]
+
   # GET /entries
   # GET /entries.xml
   def index
-    @entries = Entry.find(:all)
-
     respond_to do |format|
       format.html # index.html.erb
       format.xml  { render :xml => @entries }
@@ -40,7 +41,7 @@
   # POST /entries
   # POST /entries.xml
   def create
-    @entry = Entry.new(params[:entry])
+    @entry = @blog.entries.build(params[:entry])
 
     respond_to do |format|
       if @entry.save
@@ -78,8 +79,13 @@
     @entry.destroy
 
     respond_to do |format|
-      format.html { redirect_to(entries_url) }
+      format.html { redirect_to(blog_entries_url(@entry.blog)) }
       format.xml  { head :ok }
     end
   end
+
+  private
+  def load_blog
+    @blog = Blog.find(params[:blog_id])
+  end
 end
app/models/blog.rb
@@ -1,3 +1,4 @@
 class Blog < ActiveRecord::Base
   belongs_to :user
+  has_many :entries
 end
app/models/user.rb
@@ -5,6 +5,8 @@
   include Authentication::ByPassword
   include Authentication::ByCookieToken
 
+  has_many :blogs
+
   validates_presence_of     :login
   validates_length_of       :login,    :within => 3..40
   validates_uniqueness_of   :login
app/views/blogs/index.html.erb
@@ -9,8 +9,8 @@
 <% for blog in @blogs %>
   <tr>
     <td><%=h blog.title %></td>
-    <td><%=h blog.user %></td>
     <td><%= link_to 'Show', blog %></td>
+    <td><%= link_to 'Show Entries', blog_entries_path(blog) %></td>
     <td><%= link_to 'Edit', edit_blog_path(blog) %></td>
     <td><%= link_to 'Destroy', blog, :confirm => 'Are you sure?', :method => :delete %></td>
   </tr>
app/views/blogs/show.html.erb
@@ -3,11 +3,6 @@
   <%=h @blog.title %>
 </p>
 
-<p>
-  <b>User:</b>
-  <%=h @blog.user %>
-</p>
-
 
 <%= link_to 'Edit', edit_blog_path(@blog) %> |
 <%= link_to 'Back', blogs_path %>
app/views/blogs/new.html.erb
@@ -8,10 +8,6 @@
     <%= f.text_field :title %>
   </p>
   <p>
-    <%= f.label :user %><br />
-    <%= f.text_field :user %>
-  </p>
-  <p>
     <%= f.submit "Create" %>
   </p>
 <% end %>
app/views/blogs/edit.html.erb
@@ -8,10 +8,6 @@
     <%= f.text_field :title %>
   </p>
   <p>
-    <%= f.label :user %><br />
-    <%= f.text_field :user %>
-  </p>
-  <p>
     <%= f.submit "Update" %>
   </p>
 <% end %>
app/views/entries/index.html.erb
@@ -7,11 +7,10 @@
     <th>Blog</th>
   </tr>
 
-<% for entry in @entries %>
+<% for entry in @blog.entries %>
   <tr>
     <td><%=h entry.title %></td>
     <td><%=h entry.body %></td>
-    <td><%=h entry.blog %></td>
     <td><%= link_to 'Show', entry %></td>
     <td><%= link_to 'Edit', edit_entry_path(entry) %></td>
     <td><%= link_to 'Destroy', entry, :confirm => 'Are you sure?', :method => :delete %></td>
@@ -21,4 +20,5 @@
 
 <br />
 
-<%= link_to 'New entry', new_entry_path %>
+<%= link_to 'New entry', new_blog_entry_path(@blog) %>
+<%= link_to 'Blogs', blogs_path %>
app/views/entries/show.html.erb
@@ -8,11 +8,5 @@
   <%=h @entry.body %>
 </p>
 
-<p>
-  <b>Blog:</b>
-  <%=h @entry.blog %>
-</p>
-
-
 <%= link_to 'Edit', edit_entry_path(@entry) %> |
-<%= link_to 'Back', entries_path %>
+<%= link_to 'Back', blog_entries_path(@entry.blog) %>
app/views/entries/new.html.erb
@@ -1,6 +1,6 @@
 <h1>New entry</h1>
 
-<% form_for(@entry) do |f| %>
+<% form_for [@blog, @entry] do |f| %>
   <%= f.error_messages %>
 
   <p>
@@ -12,12 +12,8 @@
     <%= f.text_area :body %>
   </p>
   <p>
-    <%= f.label :blog %><br />
-    <%= f.text_field :blog %>
-  </p>
-  <p>
     <%= f.submit "Create" %>
   </p>
 <% end %>
 
-<%= link_to 'Back', entries_path %>
+<%= link_to 'Back', blog_entries_path(@blog) %>
app/views/entries/edit.html.erb
@@ -12,13 +12,9 @@
     <%= f.text_area :body %>
   </p>
   <p>
-    <%= f.label :blog %><br />
-    <%= f.text_field :blog %>
-  </p>
-  <p>
     <%= f.submit "Update" %>
   </p>
 <% end %>
 
 <%= link_to 'Show', @entry %> |
-<%= link_to 'Back', entries_path %>
+<%= link_to 'Back', blog_entries_path(@entry.blog) %>

うわw長w