rails 入门笔记

rails 入门笔记

官方教程链接
学习上述教程的过程中加入了一些相关知识,也缩减了一些我暂时还看不懂的东西

环境

windows
ruby2.7
rails6.1

新建项目

打开cmd,输入rails new 项目名

例如:

$ rails new myblog 

生成一个名为myblog的rails项目。

进入myblog目录,在cmd中输入rails server,即可启动rails服务器。默认在3000端口,用浏览器访问localhost:3000即可看到rails的欢迎界面。

如果你不要小心在运行服务器的时候把cmd关掉了,再启动cmd想要运行rails serer的时候,它会提醒你server已经在其他进程中运行。这个时候,你需要杀死之前运行的服务器进程,方法如下:

  1. /tmo/pids/server.pid中找到server的运行编号,下面以编号9476为例。
  2. 在cmd中查看这个命令编号,确认是否是rails
    1. 命令为:tasklist | findstr 9476
  3. 在cmd中杀死这个进程:
    1. taskkill /pid 9476 -t -f

新建控制器

cmd中输入:

$ rails generate controller Welcome index

创建一个包含“index”动作的“Welcome”控制器。

MVC结构:model-viewer-controller模式(模型-视图-控制器),关于这三部分的具体讲解在本教程中将随着web开发的进行而深入。

成功创建控制器后,你将看到rails为你新建的文件:

$ rails generate controller Welcome index
      create  app/controllers/welcome_controller.rb
       route  get 'welcome/index'
      invoke  erb
      create    app/views/welcome
      create    app/views/welcome/index.html.erb
      invoke  test_unit
      create    test/controllers/welcome_controller_test.rb
      invoke  helper
      create    app/helpers/welcome_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    scss
      create      app/assets/stylesheets/welcome.scss

控制器(controller)位于app/controllers/welcome_controller.rb文件,

视图(view)位于app/views/welcome/index.html.erb文件,打开这个文件,添加

<h1>Hello, Rails!</h1>

即可在页面中显示Hello, Rails!。我们注意到,这个文件的语法规则和html是类似的。你可以在localhost:3000/welcome/index找到这个页面。

我们也可以新建一个不带任何动作的控制器:

$ rails generate conrtroller Articles

打开app/controllers/welcome_controller.rbapp/controllers/articles_controller.rb,你会看到二者的不同之处。

打开app/controllers/articles_controller.rb,其中代码为:

class ArticlesController < ApplicationController
end

app/controllers/welcome_controller.rb中则是

class WelcomeController < ApplicationController
  def index
  end
end

从上述代码中,我们可以发现,控制器本质上是一个继承自 ApplicationController 的类。

那么我们如何从空的控制器中新建方法呢?

首先,我们在这个控制器中定义一个new方法:

class ArticlesController < ApplicationController
  def new
  end
end

然后为这个方法新建页面,在app/views/下新建articles/new.html.erb,就可以了。访问 http://localhost:3000/articles/new即可看到新建的页面。

如果发生报错Rails: Webpacker::Manifest::MissingEntryError in Home#index,那么请:

  1. 检查node.js版本,跟新到最新稳定版本
  2. 检查webpacker安装,在命令行输入bundle exec rake webpacker:install即可

设置应用主页

代开config/routes.rb文件,这是路由的配置文件。可以看到里面已经生成了一些DSL代码(Domain-Specific Language,领域专属语言):

Rails.application.routes.draw do
  get 'welcome/index'
 
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

其中get 'welcome/index'表示应用中有一个get方法,地址是localhost:3000/welcome/index

我们可以添加一行root 'welcome#index',将welcome中的index页面设置成整个应用的主页,此时,运行服务器,访问``localhost:3000看到是将welcome/index`页面。

创建资源

资源是一个术语,表示一系列类似对象的集合,如文章、人或动物。

config/routes.rb中添加article资源。

Rails.application.routes.draw do
  get 'welcome/index'
 
  resources :articles
 
  root 'welcome#index'
end

创建表单

app/views/articles/new.html.erb中添加:

<%= form_for :article, url: articles_path do |f| %>
  <p>
    <%= f.label :title %><br>
    <%= f.text_field :title %>
  </p>
 
  <p>
    <%= f.label :text %><br>
    <%= f.text_area :text %>
  </p>
 
  <p>
    <%= f.submit %>
  </p>
<% end %>

刷新页面,即可看到表单。

调用 form_for 辅助方法时,需要为表单传递一个标识对象作为参数,这里是 :article 符号。这个符号告诉 form_for 辅助方法表单用于处理哪个对象。在 form_for 辅助方法的块中,f 表示 FormBuilder 对象,用于创建两个标签和两个文本字段,分别用于添加文章的标题和正文。最后在 f 对象上调用 submit 方法来为表单创建提交按钮。

值得注意的是url这部分,url是传入的articles的地址,这意味着会将其与articles的poat方法相连。

利用rail routes查看一下路由管理的全部的地址,可以看到以下一项

 articles GET    /articles(.:format)          articles#index
          POST   /articles(.:format)          articles#create

在rails中,创建模型的时候,已经为我们创建好了基本的CRUD 动作(indexshowneweditcreateupdatedestroy),我们可以从路由中找到对应地址。

因此,事实上是与create动作绑定的。

接下来,我们在articles的controller中定义一个create动作,这样表单就可以与创建文章这个动作绑定了。

此时,我们运行服务器,提交表单,看到:

#<ActionController::Parameters {"title"=>"12", "text"=>"1"} permitted: false>

可以看到,虽然正确传递了参数,但是没有构建模型,存储数据。

创建模型

创建模型命令如下:

$ rails generate model Article title:string text:text

此时,我们创建了一个名字为Article的模型,这个模型由两个属性:string类型的titletext类型的text

同时,我们会看到rails创建了db/migrate/20210914114124_create_articles.rb打开这个文件,会看到:

class CreateArticles < ActiveRecord::Migration[6.1]
  def change
    create_table :articles do |t|
      t.string :title
      t.text :text

      t.timestamps
    end
  end
end

db/migrate中的文件是帮助记录数据库迁移中执行的具体操作,文件名以时间戳命名,方便撤销。

执行rails db:migrate,进行数据库的迁移,这条命令执行后,可以看到:

== 20210914114124 CreateArticles: migrating ===================================
-- create_table(:articles)
   -> 0.0022s
== 20210914114124 CreateArticles: migrated (0.0031s) ==========================

此时,我们才真正建立了articles表,并且表中有Article模型。

然后,我们回过头来修改create方法,让它能够将我们输入的数据保存起来。

class ArticlesController < ApplicationController
  def new
  end
  def create
    @article = Article.new(params[:article]) # 新建一个Article模型的实例,接收传入的参数
    # 注意Ruby中的类名必须是大写字母开头
    @article.save # 保存这个实例
    redirect_to @article # 重定向至show动作
  end
end

运行服务器,提交表单,发现报错:

ActiveModel::ForbiddenAttributesError in ArticlesController#create
ActiveModel::ForbiddenAttributesError

报错源码:

@article = Article.new(params[:article]) # 新建一个Article模型的实例,接收传入的参数

这是由于我们没有使用“健壮参数”(strong parameter),“健壮参数”原则要求我们告诉rails哪些参数允许咋控制器中使用。这是rails安全性设置之一,为了防止恶意攻击数据库

所以,我们要将上面这句源码修改为:

@article = Article.new(params.require(:article).permit(:title, :text))

permit方法中的字段为合法字段,用户传入的其他字段将被阻拦。

同时,为了禁止从外部调用这个方法,通常还要把它设置为 private

class ArticlesController < ApplicationController
  def new
  end
  def create
    @article = Article.new(article_params) # 新建一个Article模型的实例,接收传入的参数
    # 注意Ruby中的类名必须是大写字母开头
    @article.save # 保存这个实例
    redirect_to @article # 重定向至show动作
  end
  
  private 
    def article_params 
      params.require(:article).permit(:title, :text)
    end
end

需要注意的是,在ruby中private修饰的是自private之下的所有方法!也就是说,如果你将create方法放到article_params之后,那么create也将变成私有方法。然而,标准的 CRUD 动作(indexshowneweditcreateupdatedestroy),都必须是公开方法,不可以放在private之后。

在路由中($ rails routes)发现,关于article的show方法是:

article GET    /articles/:id(.:format)      articles#show

那么我们可以编写show方法,来展示文章。

def show 
  @article = Article.find(params[:id]) # 选取对应id的文章
end

新建app/views/articles/show.html.erb,写入

<p>
  <strong>Title:</strong>
  <%= @article.title %>
</p>
 
<p>
  <strong>Text:</strong>
  <%= @article.text %>
</p>

功能完善

展示所有文章列表

rails routes中找到index方法

articles GET    /articles(.:format)          articles#index

articles_controller.rb中写入:

def index
    @articles = Article.all
end

index.html.rb中写入:

<h1>Listing articles</h1>
 
<table>
  <tr>
    <th>Title</th>
    <th>Text</th>
  </tr>
 
  <% @articles.each do |article| %>
    <tr>
      <td><%= article.title %></td>
      <td><%= article.text %></td>
      <td><%= link_to 'Show', article_path(article) %></td>
    </tr>
  <% end %>
</table>

link_to 方法是 Rails 内置的视图辅助方法之一,用于创建基于链接文本和地址的超链接。在这里地址指的是文章列表页面的路径。

添加链接

在welcome页中添加向文章列表的链接。

welcome/index.html.erb中添加:

<%= link_to 'My Blog', controller: 'articles' %>

请自行联系添加一些在各个页面中添加一些跳转和返回链接。

链接到当前控制器的动作时不需要指定 :controller 选项,因为 Rails 默认使用当前控制器.

添加验证

打开app/models/article.rb,修改为:

class Article < ApplicationRecord
  validates :title, presence: true, length: { minimum: 5 }
end

用于检查title是否存在、长度不少于5字符。

修改controller中的方法:

    if @article.save # 保存这个实例
      redirect_to @article # 重定向至show动作
     else
       render 'new'
     end

将new.html.erb改为:

<%= form_for :article, url: articles_path do |f| %>
 
  <% if @article.errors.any? %>
    <div id="error_explanation">
      <h2>
        <%= pluralize(@article.errors.count, "error") %> prohibited
        this article from being saved:
      </h2>
      <ul>
        <% @article.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
      </ul>
    </div>
  <% end %>
 
  <p>
    <%= f.label :title %><br>
    <%= f.text_field :title %>
  </p>
 
  <p>
    <%= f.label :text %><br>
    <%= f.text_area :text %>
  </p>
 
  <p>
    <%= f.submit %>
  </p>
 
<% end %>
 
<%= link_to 'Back', articles_path %>

模型之间的关联

创建关联模型

在rails中模块之间可以相互关联,允许一个模型包含若干个子模型,比如对于一个文章可以含有若干条评论,则model article可以包含 model comments。

子模块创建方式:在正常创建命令后加父模块名:references,即

$ bin/rails generate model Comment commenter:string body:text article:references

然后,进行migrate就好了。

打开创建comment对应的migrate文件,发现只是比创建article多了一行t.references :article, null: false, foreign_key: true

class CreateComments < ActiveRecord::Migration[6.1]
  def change
    create_table :comments do |t|
      t.string :commenter
      t.text :body
      t.references :article, null: false, foreign_key: true

      t.timestamps
    end
  end
end

如果忘记加关联,想要重新生成数据表怎么办?这里介绍一下通过修改migration文件来进行数据库表单修改操作。

  1. 如果还没进行migrate操作,可以打开/db/migrate/文件夹,找到对应的migrate文件,增加t.references :article, foreign_key: true
  2. 如果已经进行了migrate操作,那么可以在create_tabble前加一行drop_table :comments,即可删除此前创建的表,并重新创建

最后,不要忘记进行migrate操作

接下来需要修改app/models/comment.rb

class Comment < ApplicationRecord
  belongs_to :article
end

表示一条评论属于一篇文章。

修改app/model/article.rb

class Article < ApplicationRecord
  has_many :comments
  validates :title, presence: true, length: {minimum: 5}
end

表示一篇文章可以有多条评论。

修改控制器

创建控制器Comments,并添加:

class CommentsController < ApplicationController
    def create
        @article = Article.find(params[:article_id])
        @comment = @article.comments.create(comment_params)
        redirect_to article_path(@article)
    end
    private 
    def comment_params
        params.require(:comment).permit(:commenter, :body)
    end
end

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

<p>
  <strong>Title:</strong>
  <%= @article.title %>
</p>
 
<p>
  <strong>Text:</strong>
  <%= @article.text %>
</p>
 
<h2>Comments</h2>
<% @article.comments.each do |comment| %>
  <p>
    <strong>Commenter:</strong>
    <%= comment.commenter %>
  </p>
 
  <p>
    <strong>Comment:</strong>
    <%= comment.body %>
  </p>
<% end %>
 
<h2>Add a comment:</h2>
<%= form_for([@article, @article.comments.build]) do |f| %>
  <p>
    <%= f.label :commenter %><br>
    <%= f.text_field :commenter %>
  </p>
  <p>
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>
 
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>

即可进行评论的添加与查看。

重构

我们发现app/views/articles/show.html.erb中的内容过多,而且其中很多是comment的内容,因此,我们可以将关于comment的内容取出:

创建app/views/comments/_comment.html.erb

<p>
  <strong>Commenter:</strong>
  <%= comment.commenter %>
</p>
 
<p>
  <strong>Comment:</strong>
  <%= comment.body %>
</p>

创建app/views/comments/_form.html.erb

<%= form_for([@article, @article.comments.build]) do |f| %>
  <p>
    <%= f.label :commenter %><br>
    <%= f.text_field :commenter %>
  </p>
  <p>
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>

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

<p>
  <strong>Title:</strong>
  <%= @article.title %>
</p>
 
<p>
  <strong>Text:</strong>
  <%= @article.text %>
</p>
 
<h2>Comments</h2>
<%= render @article.comments %>
 
<h2>Add a comment:</h2>
<%= render 'comments/form' %>
 
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>

关联模型的删除

删除评论

app/views/comments/_comment.html.erb中添加;

<p>
  <%= link_to 'Destroy Comment', [comment.article, comment],
               method: :delete,
               data: { confirm: 'Are you sure?' } %>
</p>

comment_controller.rb中添加destory方法:

def destroy
    @article = Article.find(params[:article_id])
    @comment = @article.comments.find(params[:id])
    @comment.destroy
    redirect_to article_path(@article)
  end
删除文章同时删除相关评论

app/model/article.rb中修改:

class Article < ApplicationRecord
  has_many :comments, dependent: :destroy
  validates :title, presence: true,
                    length: { minimum: 5 }
end

基本身份验证

仅介绍一种基本方法:

在controller中添加如下代码:

class ArticlesController < ApplicationController
 
  http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]
 
  def index
    @articles = Article.all
  end
 
  # 为了行文简洁,省略以下内容

class CommentsController < ApplicationController
 
  http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy
 
  def create
    @article = Article.find(params[:article_id])
    # ...
  end
 
  # 为了行文简洁,省略以下内容

进阶指南

请不要独立完成一切!!!请不要独立完成一切!!

rails可以帮你搞定大多数问题,请不要独自完成一切。

分类教程

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值