Rails 101

对自己进入全栈工程师进行一个记录。

前期配置

rails new rails101
git init
git add .
git commit -m "Initial Commit"

穿衣服Bootstrap

gem 'bootstrap-sass'

Bootstrap 的 CSS 套件

  • 裝進專案裡面 app/assets/stylesheets/application.scss
@import "bootstrap-sprockets";  
@import "bootstrap";   

mkdir app/views/common
touch app/views/common/_navbar.html.erb

app/views/common/_navbar.html.erb

<nav class="navbar navbar-default" role="navigation">
    <div class="container-fluid">
        <div class="navbar-header">
            <a class="navbar-brand" href="/">Rails 101</a>
        </div>

        <div class="collapse navbar-collapse">
            <ul class="nav navbar-nav navbar-right">
                <li>
                    <%= link_to("登录", '#') %>
                </li>
            </ul>
        </div>
    </div>
</nav>

touch app/views/common/_footer.html.erb

app/views/common/_footer.html.erb

<footer class="container" style="margin-top: 100px;">
    <p class="text-center">Copyright ©2017 Rails101
        <br>Design by
        <a href="http://courses.growthschool.com/courses/rails-101/" target=_new>xdite</a>
    </p>
</footer>

app/views/layouts/application.html.erb
layout用来做后台管理

<body>

        <div class="container-fluid">
            <%= render "common/navbar" %>
            <%= yield %>
        </div>

        <%= render "common/footer" %>

    </body>
</html>

将alert的js套件”挂”进项目的步骤、

  • 修改 app/assets/javascripts/application.js加入
//= require bootstrap/alert

touch app/views/common/_flashes.html.erb

app/views/common/_flashes.html.erb

<% if flash.any? %>
  <% user_facing_flashes.each do |key, value| %>
    <div class="alert alert-dismissable alert-<%= flash_class(key) %>">
      <button class="close" data-dismiss="alert">×</button>
      <%= value %>
    </div>
  <% end %>
<% end %>

touch app/helpers/flashes_helper.rb

app/helpers/flashes_helper.rb

module FlashesHelper
  FLASH_CLASSES = { alert: "danger", notice: "success", warning: "warning"}.freeze

  def flash_class(key)
    FLASH_CLASSES.fetch key.to_sym, key
  end

  def user_facing_flashes
    flash.to_hash.slice "alert", "notice", "warning" 
  end
end

在layout文件中 <%= yield %> 前加入

<%= render "common/flashes" %>

建立群架构

rails g model group title:string description:text
rake db:migrate
rails g controller groups

app/controllers/groups_controller.rb

class GroupsController < ApplicationController
  def index
    @groups = Group.all
  end

  def show
    @group = Group.find(params[:id])
  end

  def edit
    @group = Group.find(params[:id])
  end

  def new
    @group=Group.new
  end

  def create
    @group= Group.new(group_params)
    if @group.save
      redirect_to groups_path
    else
      render :new
    end
  end

  def update
    @group=Group.find(params[:id])
    if @group.update(group_params)
      redirect_to groups_path, notice: "Update Success"
    else
      render :edit
    end
  end

  def destroy
    @group=Group.find(params[:id])
    @group.destroy
    flash[:alert]= "Group deleted"
    redirect_to groups_path
  end

  private
  def group_params
    params.require(:group).permit(:title, :description)
  end
end

touch app/views/groups/index.html.erb

<div class="col-md-12">
  <div class="group">
    <%= link_to("New group", new_group_path, class: "btn btn-primary pull-right") %>
  </div>
  <table class="table table-hover">
    <thead>
      <tr>
        <td>#</td>
        <td>Title</td>
        <td>Description</td>
      </tr>
    </thead>
    <tbody>
      <% @groups.each do |group| %>
        <tr>
          <td>#</td>
          <td><%= link_to(group.title, group_path(group)) %></td>
          <td><%= group.description %></td>
          <td>
              <%= link_to("Edit", edit_group_path(group), class: "btn btn-sm btn-default")%>
              <%= link_to("Delete", group_path(group),    class: "btn btn-sm btn-default", 
                          method: :delete, data: { confirm: "Are you sure?" } )%>
          </td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>

config/routes.rb

resources :groups do
root 'groups#index'
end
  • 测试一下

rails c
Group.create(title: "Board 1", description: "Board 1 body")

手动实作讨论群的“新增”“修改”“删除”功能

touch app/views/groups/new.html.erb

<div class= "col-md-4 col-md-offset-4">
    <h2> 新增讨论版 </h2>
    <hr>
    <%= render "form" %>
</div>
touch app/views/groups/edit.html.erb
<div class="col-md-4 col-md-offset-4">
    <h2>编辑讨论版</h2>
    <hr>
    <%= render "form" %>
</div>

touch app/views/groups/show.html.erb

<div class="col-md-12">
  <div class="group">
    <%= link_to("Edit", edit_group_path(@group), class: "btn btn-primary pull-right")%>
  </div>
  <h2><%= @group.title %></h2>
  <p><%= @group.description %></p>
</div>

装gem 'simple_form'

  • step1: gem 'simple_form'
  • step2: bundle install
  • step3: rails generate simple_form:install --bootstrap

touch app/views/groups/_form.html.erb

<%= simple_form_for @group do |f| %>
  <div class="form-group">
    <%= f.input :title, input_html: { class: "form-control"} %>
    <%= f.input :description, input_html: { class: "form-control"} %>
  </div>
  <%= f.submit "Submit", class: "btn btn-primary", date: {disable_with: "Submiting..."} %>
  <% end %>

做会员系统

gem 'devise'
bundle install
rails g devise:install
rails g devise user
rake db:migrate

然后重开 rails server
修改app/controllers/groups_controller.rb

before_action :authenticate_user! , only: [:new]

下拉菜单

app/views/common/_navbar.html.erb

<nav class="navbar navbar-default" role="navigation">
    <div class="container-fluid">
        <div class="navbar-header">
            <a class="navbar-brand" href="/">点我试试呀</a>
        </div>

        <div class="collapse navbar-collapse">
            <ul class="nav navbar-nav navbar-right">
              <% if !current_user %>
                <li><%= link_to("注册", new_user_registration_path) %> </li>
                <li><%= link_to("登录", new_user_session_path) %></li>
              <% else %>
                <li class="dropdown">
                  <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                      Hi!, <%= current_user.email %>
                      <b class="caret"></b>
                  </a>
                  <ul class="dropdown-menu">
                      <li> <%= link_to("退出", destroy_user_session_path, method: :delete) %> </li>
                  </ul>
                </li>
              <% end %>
                </li>
            </ul>
        </div>
    </div>
</nav>
  • 加入js套件

//= require bootstrap/dropdown

让“群组”与“使用者”产生关联

rails g migration add_user_id_to_group

db/migrate/一串数字_add_user_id_to_group

add_column :groups, :user_id, :integer

rake db:migrate

app/models/user.rb

has_many :groups

app/models/group.rb

belongs_to :user
validates :title, presence: true

app/controllers/groups_controller.rb

before_action :authenticate_user! , only: [:new, :create]

app/controllers/groups_controller.rb
在 create 中,多加入一行

@group.user = current_user

修改 app/views/groups/index.html.erb 然后把 Creator 的信息加进去

<td>Creator </td>
。。。。。。
<td> <%= group.user.email %> </td>

如果出现报错就如下处理

rails console
Group.delete_all

  • 路人不应该可以看到“编辑”“删除”按钮
    app/views/groups/index.html.erb
<% if current_user && current_user == group.user %>  
<% end %>
  • 修改 app/controllers/groups_controller.rb
before_action :authenticate_user! , only: [:new, :create, :edit, :update, :destroy]
before_action :find_group_and_check_permission, only: [:edit, :update, :destroy]

打开 app/controllers/groups_controller.rb 在 private 下,新增一个 find_group_and_check_permission

def find_group_and_check_permission
    @group = Group.find(params[:id])

    if current_user != @group.user
      redirect_to root_path, alert: "You have no permission."
    end
  end
  • 拔掉路人show里面的edit
  • 修改 app/views/groups/show.html.erb ,然后加入
<% if current_user && current_user == @group.user %>

设计Post 的 model 架构

rails g model post content:text group_id:integer user_id:integer
rake db:migrate

  • Group / Post / User 三者间的关系

group.rb

has_many :posts

user.rb

has_many :posts

post.rb

belongs_to :user
belongs_to :group

将 ==resources :posts== 加入 resources :groups 内

Rails.application.routes.draw do
  devise_for :users
  resources :groups do
    resources :posts
  end
  root 'groups#index'
end

rake routes

修改 app/views/groups/show.html.erb

<%= link_to("Write a Post", new_group_post_path(@group), class: "btn btn-default pull-right")%>

rails g controller posts

新增 new 与 create action 在posts_controllerapp/controllers/posts_controller.rb

class PostsController < ApplicationController
  before_action :authenticate_user!, :only => [:new, :create]

  def new
    @group = Group.find(params[:group_id])
    @post = Post.new
  end

  def create
    @group = Group.find(params[:group_id])
    @post = Post.new(post_params)
    @post.group = @group
    @post.user = current_user

    if @post.save
      redirect_to group_path(@group)
    else
      render :new
    end
  end

  private
  def post_params
    params.require(:post).permit(:content)
  end
end

touch app/views/posts/new.html.erb

<h2 class="text-center">新增文章</h2>

<div class="col-md-4 col-md-offset-4">
  <%= simple_form_for [@group,@post] do |f| %>
    <div class="form-group">
      <%= f.input :content, input_html: { class: "form-control"} %>
    </div>
    <div class="form-actions">
      <%= f.submit "Submit", disable_with: "Submiting...", class: "btn btn-primary"%>
    </div>
  <% end %>
</div>

修改 app/controllers/groups_controller.rb的show里面

@posts = @group.posts

修改groups/show.html.erb

<table class="table">
    <thead>
      <tr>
        <th>文章内容</th>
        <th>发表者</th>
        <th>发表时间</th>
      </tr>
    </thead>
    <tbody>
      <% @posts.each do |post| %>
        <tr>
          <td><%= post.content %></td>
          <td><%= post.user.email %></td>
          <td><%= post.created_at %></td>
        </tr>
      <% end %>
    </tbody>
    </table>

限制 post 的 content 要是为空,就不得送出修改 app/models/post.rb 加入

validates :content, presence: true

发表时间“倒序”排列
修改 app/models/post.rb,加入一行

scope :recent, -> { order("created_at DESC")}

然后修改 app/controllers/groups_controller.rb 中的 show,变成

@posts = @group.posts.recent

加入文章分页功能

gem 'will_paginate'

bundle install
rails server

  • 修改 app/controllers/groups_controller.rb 中的 show
@posts = @group.posts.recent.paginate(:page => params[:page], :per_page => 5)
  • 修改 app/views/groups/show.html.erb
    在最下面 </table> 下加入以下三行代码:
<div class="text-center">
      <%= will_paginate @posts %>
</div>

“加入群组”或“退出群组”

gem、controller、show三部分改动

rails g model group_relationship group_id:integer user_id:integer
rake db:migrate

  • 修改app/views/groups/show.html.erb
<span class="pull-right">
      <% if current_user && current_user.is_member_of?(@group) %>
        <label class="label label-success"> 群组成员 </label>
        <%= link_to("想要Quit Group", quit_group_path(@group), method: :post, class: "btn btn-default") %>
      <% else %>
        <label class="label label-warning"> 不是群组成员 </label>
        <%= link_to("Join123 Group", join_group_path(@group), method: :post, class: "btn btn-default") %>
      <% end %>
    </span>
  • app/models/user.rb
has_many :group_relationships
has_many :participated_groups, :through => :group_relationships, :source => :group

  def is_member_of?(group)
    participated_groups.include?(group)
  end

  def join!(group)
    participated_groups << group
  end

  def quit!(group)
    participated_groups.delete(group)
  end
  • app/models/group_relationship.rb
belongs_to :group
belongs_to :user
  • app/models/group.rb
has_many :group_relationships
has_many :members, through: :group_relationships, source: :user
  • app/controllers/groups_controller.rb
    def join
@group = Group.find(params[:id])
    if !current_user.is_member_of?(@group)
      current_user.join!(@group)
      flash[:notice] = "加入本讨论版成功!"
    else
      flash[:warning!] = "你已经是本讨论版成员!"
    end
    redirect_to group_path(@group)
  end

    def quit
      @group = Group.find(params[:id])
      if current_user.is_member_of?(@group)
        current_user.quit!(@group)
        flash[:alert] = "已退出本讨论版!"
      else
        flash[:warning] = "你不是本讨论版成员,怎么退出 XD"
      end
      redirect_to group_path(@group)
    end
  • 修改位於第二行的 before_action ,加入 join 和 quit 也需要验证
    config/routes.rb
resources :groups do
    member do
      post :join
      post :quit
    end

让 User 在建立 group 后自动成为 group 的一员

  • app/controllers/groups_controller.rb
current_user.join!(@group)

使用者可以在“自己的后台”看过曾经发表的文章、以及创立的社团

rails g controller account/groups

config/routes.rb
  namespace :account do
    resources :groups
  end

在“下拉选单选项”中多加入一个My Groups:

  • app/views/common/_navbar.html.erb
<li> <%= link_to("My Groups", account_groups_path) %></li>
    <li class="divider"> </li>
  • 记得要加入: before_action :authenticate_user!,限制必须要得登录使用者,才能看。
    app/controllers/account/groups_controller.rb
before_action :authenticate_user!
  def index
    @groups = current_user.participated_groups
  end

制作管理者观看后台界面

touch app/views/account/groups/index.html.erb

<div class="col-md-12">

  <h2 class="text-center"> 我加入的讨论版 </h2>

  <table class="table">
    <thead>
      <tr>
        <th> # </th>
        <th> Title </th>
        <th> Description </th>
        <th> Post Count </th>
        <th> Last Update </th>
      </tr>
    </thead>

    <tbody>
      <% @groups.each do |group| %>
        <tr>
          <td> # </td>
          <td> <%= link_to(group.title, group_path(group)) %> </td>
          <td> <%= group.description %> </td>
          <td> <%= group.posts.count %> </td>
          <td> <%= group.updated_at %> </td>
        </tr>
      <% end %>
    </tbody>
  </table>
</div>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容