为您推荐:
精华内容
最热下载
问答
  • Active Record是Rails采用的ORM(对象关系映射)层,它不仅完全遵循了标准的 ORM模型(将数据库的表映射到类,记录映射到对象,字段映射到对象属性,而类方法用来执行表级别的操作,实例方法用来执行针对单条记录的...

    模型、视图和控制器 (MVC架构)

    模型 —— 负责维持应用程序的状态

    模型是数据,但又不只是数据,有时我们会把业务规则也放进模型中,这可以保证应用程序的其他部分不会有数据无效的情况出现。比如:“对于100元以下的商品不予以打折”这个约束条件就由模型来执行。

    视图 —— 负责生成用户界面

    视图通常会根据模型中的数据来生成,它的唯一工作就是显示数据。但出于不同的目的,可能有多个视图来访问同一个模型数据。比如:一个视图用来显示商品信息,另一个管理员视图用来专门添加和编辑商品信息。

    控制器 —— 负责协调整个应用程序的运转

    控制器用来接收外界的事件(比如:用户输入),与模型进行交互,并将合适的视图展示给用户。

    下图是MVC框架的工作原理:
    MVC框架的工作原理

    Ruby On Rails也是一种MVC框架

    Ruby On Rails框架的工作原理如下图所示:
    Ruby On Rails框架的工作原理


    Active Record

    Active Record是Rails采用的ORM(对象关系映射)层,它不仅完全遵循了标准的ORM模型(将数据库的表映射到类,记录映射到对象,字段映射到对象属性,而类方法用来执行表级别的操作,实例方法用来执行针对单条记录的操作),还根据人们常用的命名约定提供了很有意义的默认配置,将开发者执行的配置量降到了最低。

    展开全文
    heming87 2018-09-03 18:31:56
  • Rails 5 敏捷开发》学习笔记 - 第2章 即时满足 如何创建一个新的应用程序 使用命令:rails new 如:work> rails new demo 这将在work目录下创建一个名为demo的应用程序...

    如何创建一个新的应用程序

    使用命令:rails new

    如:work> rails new demo

    这将在work目录下创建一个名为demo的应用程序的目录。


    启动服务器

    使用命令:rails server

    如:在上述demo目录下,使用命令rails server,将启动系统默认使用的服务器。

    如果系统中安装了多个web服务器(而且Rails能够正确地找到它),可以使用命令“rails server 服务器名”来启动指定的服务器。如:使用rails server webrick,将启动webrick服务器。


    通过浏览器来访问服务器

    在启动服务器后,从Terminal的输出信息中,可以看到是在哪个端口上启动了服务器。

    如:
    demo>​​ ​​bin/rails​​ ​​server​
    ​ => Booting Puma
    ​ => Rails 5.0.0.1 application starting in development on http://localhost:3000
    ​ => Run rails server -h for more startup options
    ​ Puma starting in single mode…
    ​ * Version 3.4.0 (ruby 2.3.1-p112), codename: Owl Bowl Brawl
    ​ * Min threads: 5, max threads: 5
    ​ * Environment: development
    ​ * Listening on tcp://localhost:3000
    ​ Use Ctrl-C to stop

    上述信息显示,在本机的3000端口上启动了一个Puma服务器。所以,在本机用浏览器访问http://localhost:3000,即可访问该服务器。

    如果希望局域网内的其他电脑也可以访问该服务器的话,可以在启动服务器的时候,指定0.0.0.0作为要绑定到的主机。如:“demo>​​ ​​bin/rails​​ ​​server​​ ​​-b​​ ​​0.0.0.0​”。


    创建动态的网页内容

    首先,创建一个静态的网页

    Rails是一个MVC(模型-视图-控制器)框架,当Rails在收到浏览器的请求后,会先对浏览器的请求进行解读,然后去找到合适的控制器,接着再去调用控制器里的动作(即:某个控制器类里面的方法),最后再去调用和该动作同名的视图模板,将结果显示到浏览器上。

    以创建一个简单的Web应用程序“Hello, World!”为例,我们需要编写一个控制器和视图。暂时不需要编写模型,因为目前不需要处理任何数据。

    在demo目录下,使用命令rails generate即可创建一个名为say的控制器。同时,我们还定义了这个控制器所要完成的两个动作hello和goodbye。

    demo>​​ ​​rails​​ ​​generate​​ ​​controller​​ ​​say​​ ​​hello​​ ​​goodbye​

    创建好后,Rails会自动生成两个与动作hello和goodbye相关联的视图模板hello.html.erb和goodbye.html.erb,位于demo/app/views/say目录下。

    在这两个模板中,有一些默认的内容,可以对其做任意的修改。通过访问http://localhost:3000/say/hellohttp://localhost:3000/say/goodbye,就可以在浏览器中看到相应的网页内容。(请注意:在测试环境下,路径中没有包含应用程序名demo —— 我们直接导向到了控制器。)

    然后,给静态的网页添加上动态的内容

    例如:如果要在每次加载http://localhost:3000/say/hello后,在页面上显示出当前的时间,就可以在hello.html.erb模板中加入下面的内容:

    <h1>Hello from Rails!</h1>
    »   <p>
    »     It is now ​<%=​ Time.now ​%>​
    »   </p>

    不过,有一个更好的方案是:把“获取时间”的Time.now方法放在控制器中,而让视图只承担显示信息的职责

    所以,对控制器的文件say_controller.rb的hello动作方法修改如下:

    classSayController < ApplicationController
    ​     ​defhello
    »       @time = Time.now
    ​     ​end​
    ​   
    ​     ​defgoodbye
    ​     ​end​
    ​   ​end

    也就是把时间值放在名为@time的实例变量中。

    然后,再在hello.html.erb模板中,使用这个@time实例变量来替代输出中的时间,具体如下:

    <h1>Hello from Rails!</h1><p>
    »     It is now ​<%=​ @time ​%>​
    ​   </p>

    默认安装好Rails后,会自动安装上一个ERb过滤器。当.erb文件输入到ERb过滤器后,经过过滤,从过滤器输出的是经过转换的内容。在.erb文件中,普通的内容经过ERb过滤器后不会有任何变化,而符号<%=和%>之间的内容则会被当作Ruby代码去执行,执行的结果将转换成字符串。


    添加超链接

    如果我们要想在hello页面中插入一个超链接,以便能跳转到goodbye页面。我们可以在hello.html.erb模板中,加入下面的内容:

        ...
        <p>
    ​     Say <a href=​"/say/goodbye"​>Goodbye</a>!     
    ​   </p>
    ​   ...

    因为目前Rails会按照命名惯例,将URL解析为目的控制器和该控制器中的行为名称这两部分,所以这里的链接被定义为了“/say/goodbye”。

    但是,这种方式存在一些弊端。如果我们将来把应用程序移到了服务器的另一个目录下,这样的URL就会失效;又或者将来新版的Rails改变了目前这种对URL的解读方式,这也将导致这样的URL失效。

    所以,一个更好的方案是使用link_to()方法。如在hello.html.erb模板中,加入下面的内容:

        ...
        <p>
          Time to say
          ​<%=​ link_to ​"Goodbye"​, say_goodbye_path ​%>​!
        </p>
        ...

    link_to()方法有两个参数:第一个参数是超链接要显示出来的文字,第二个参数则是超链接的地址。这个例子中的say_goodbye_path,是Rails提供给视图的一个预计算值,它会自动计算到/say/goodbye的路径。另外,与Java等语言有所不同的是,Ruby并不要求必须把方法的参数用()括起来。


    错误恢复及调试

    代码有错的情况

    如果我们的代码中有一些笔误,例如:在say_controller.rb文件中,将Time.now误写成了Time.know,那么在刷新页面http://localhost:3000/say/hello后,将会看到下面这样的界面:
    图1
    在上图中,我们看到页面上给出了具体的错误内容,以及发生错误的地方,并给出了相应的修改意见。

    在页面的最下方,是Rails的web控制台。可以在这个控制台中尝试页面上给出的修改意见来查看结果,还可以在这个控制台中计算表达式。

    出于安全考虑,在默认情况下,只有从运行web服务器的那台电脑上去访问页面时,才会显示出来这个web控制台。如果要让所有人在他们自己的电脑上都能看到这个web控制台,需要在运行服务器的这台电脑上,往文件config/environments/development.rb中添加下面的内容:config.web_console.whitelisted_ips = ​%w( 0.0.0.0/0 ::/0 )​,并重启服务器。

    访问地址有错的情况

    如果我们在浏览器的地址栏中,输入了错误的地址,如将“http://localhost:3000/say/hello”错写成了“http://localhost:3000/say/hell0”,将出现下面这样的界面:
    图2
    页面提示“没有匹配的路由”,并列出了一些可能是正确的路由以及它们所关联的控制器的动作。在Path Match输入框中输入部分URL,将看到一个与输入内容相匹配的路由列表,这有助于快速找到我们想要的路由。


    小练习

    可以尝试下面的一些任务:

    • 加法:<%= 1+2 %>
    • 连接字符串:<%= “cow” + “boy” %>
    • 表达一个小时内的时间:<%= 1.hour.from_now.localtime %>
    • 调用Ruby方法Dir.glob('*')会返回一个列表来显示出当前目录下的所有文件。用这个方法来设置控制器中的一个实例变量,如:@files = Dir.glob(​’*’​)。然后编写对应的模板,从而在浏览器中显示出所有的文件名。在模板中,可以使用下面的代码来遍历一个集合:
    <%​ for file in @files%>​
    ​   file name is: ​<%=file%>​
    ​<%​ ​end​ ​%>
    展开全文
    heming87 2018-08-23 19:08:23
  • 这一章主要就是以开发一个名叫Depot的购物车应用程序为例,大致介绍了开发一个应用程序的流程。 增量式开发 在开始编码前,并不应该尝试弄清楚所有的细节,而是只要一旦有足够的可以开始开发的需求规格说明书,...

    这一章主要就是以开发一个名叫Depot的购物车应用程序为例,大致介绍了开发一个应用程序的流程。

    增量式开发

    在开始编码前,并不应该尝试弄清楚所有的细节,而是只要一旦有足够的可以开始开发的需求规格说明书,即可立即着手实现某些功能。毕竟,在整个开发过程中,细节是随时会发生变化的。

    用例、页面流程和数据

    在写出一个应用程序的需求规格说明书的大轮廓后,先将着眼于高层次的用例,并勾画出网页间的流程,同时尝试确定应用程序需要哪些数据。

    优先级

    因为可能必须在开发出某些功能后,才能开发其他功能,所以我们需要确定开发的优先级,明确必须优先开发哪些功能。

    展开全文
    heming87 2018-09-06 15:09:18
  • 命令创建一个Rails应用程序的时候,Rails还会同时生成一个基础的测试架构,这些测试代码位于 test 目录下,但它们都还只是一个雏形,并不完善。 其中, test/models 目录下有一个 “模型名_test.rb” 文件,是...

    本章主要介绍了如何对功能进行验证和单元测试。这两项工作的目的,主要是为了让模型更加坚固,以确保数据中发生的错误永远都不会提交给数据库。

    验证

    应该把验证代码放置在模型类中

    因为模型层扮演了代码和数据库之间的看门人的角色。那些应用程序要用到的数据,无论是从数据库中读取的,还是要往数据库中写入的,都首先会进入到模型层。所以,只要把验证代码放在模型类中,在把数据写入到数据库中之前,对数据进行了验证,就可以避免坏数据对数据库造成破坏。

    验证代码使用validates方法

    就之前的创建商品的例子而言,我们只需要往模型类Product类的源码app/models/products.rb中,插入以下代码,就可以在使用页面上的功能时获得相应的验证信息:

    class Product < ApplicationRecord
      validates :title, :description, :image_url, presence: true
      validates :price, numericality: {greater_than_or_equal_to: 0.01}
      validates :title, uniqueness: true
      validates :image_url, allow_blank: true, format:{
          with: %r{\.(gif|jpg|png)\Z}i,
          message: 'must be a URL for GIF, JPG or PNG image.'
      }
    end
    • validates这个方法是标准的Rails验证器,它可以根据一个或多个条件来验证模型的一个或多个字段。
    • presence: true是让验证器核实每个已命名的字段都必须存在,而且内容不能为空。
    • numericality是用来判断输入的数字是不是有效的数字。
    • greater_than_or_equal_to选项的值设为0.01而不是0,是因为数据库只能存储小数点后的两位数字,如果将这个比较值设为0,当输入0.001时,数据库也将把0.001保存为0,从而导致功能上的错误。
    • uniqueness: true是对字段进行唯一性的验证。
    • format选项可以判断字段是否和正则表达式相匹配。
    • allow_blank: true书中表示该选项可以允许某个字段为空(但本人实测无效)

    用rails test命令进行简单的测试

    利用rails test命令可以测试一下刚才加入的那些验证代码,是否会给整个程序的代码带来一个错误。

    在运行后该命令后,terminal报出了两个错误,分别是在test/controllers/products_controller_test.rb文件里的should create product处和should update product处。这是因为我们在Product模型类中增加了上面的验证方法后,还没有增减相应的测试数据,所以暂时还无法执行测试脚本中,与“创建商品”功能和“更新商品”功能相关的这两部分测试代码。在products_controller_test.rb中增加具体的测试数据后,便可解决掉这个问题。增加测试数据后的products_controller_test.rb代码如下:

    require 'test_helper'
    
    class ProductsControllerTest < ActionDispatch::IntegrationTest
      setup do
        @product = products(:one)
        @update = {
            title: 'Lorem Ipsum',
            description: 'Wibbles are fun!',
            image_url: 'lorem.jpg',
            price: 19.95
        }
      end
    
      test "should get index" do
        get products_url
        assert_response :success
      end
    
      test "should get new" do
        get new_product_url
        assert_response :success
      end
    
      test "should create product" do
        assert_difference('Product.count') do
          post products_url, params: { product: @update }
        end
    
        assert_redirected_to product_url(Product.last)
      end
    
      test "should show product" do
        get product_url(@product)
        assert_response :success
      end
    
      test "should get edit" do
        get edit_product_url(@product)
        assert_response :success
      end
    
      test "should update product" do
        patch product_url(@product), params: { product: @update }
        assert_redirected_to product_url(@product)
      end
    
      test "should destroy product" do
        assert_difference('Product.count', -1) do
          delete product_url(@product)
        end
    
        assert_redirected_to products_url
      end
    end

    再次运行rails test命令,便一切正常。


    单元测试

    在用rails new命令创建一个Rails应用程序的时候,Rails还会同时生成一个基础的测试架构,这些测试代码位于test目录下,但它们都还只是一个雏形,并不完善。

    其中,test/models目录下有一个“模型名_test.rb”文件,是用来对“模型名.rb”文件进行测试的代码。那么,在“创建商品”这个例子中,就是通过test/models/product_test.rb文件里的代码来对app/models/product.rb文件里的代码进行单元测试。

    测试功能点1:每个字段都不能为空

    往product_test.rb文件中加入以下测试代码:

    require 'test_helper'
    
    class ProductTest < ActiveSupport::TestCase
      # test "the truth" do
      #   assert true
      # end
    
      test "product attributes must not be empty" do
        product = Product.new
        assert product.invalid?
        assert product.errors[:title].any?
        assert product.errors[:description].any?
        assert product.errors[:price].any?
        assert product.errors[:image_url].any?
      end
    end
    • 在测试框架中,我们是通过assert这个断言方法,来判断模型的代码是否能通过测试的。当assert的参数为真的时候,断言执行通过,表示模型的代码可以通过测试;反之,则断言执行失败,表示模型的代码不能通过测试。

    执行rails test:models命令,开始执行测试,并随后输出测试结果。

    测试功能点2:商品价格需大于零

    往product_test.rb文件中加入以下测试代码:

    require 'test_helper'
    
    class ProductTest < ActiveSupport::TestCase
      test "product price must be positive" do
        product = Product.new(title:"My Book Title",
                              description: "yyy",
                              image_url: "zzz.jpg")
        product.price = -1
        assert product.invalid?
        assert_equal ["must be greater than or equal to 0.01"],
                     product.errors[:price]
    
        product.price = 0
        assert product.invalid?
        assert_equal ["must be greater than or equal to 0.01"],
                     product.errors[:price]
    
        product.price = 1
        assert product.valid?
      end
    end

    执行rails test:models命令,开始执行测试。

    测试功能点3:图像的URL需以指定内容结尾

    往product_test.rb文件中加入以下测试代码:

    require 'test_helper'
    
    class ProductTest < ActiveSupport::TestCase
      def new_product(image_url)
        Product.new(title: "My Book Title",
                    description: "yyy",
                    price: 1,
                    image_url: image_url)
      end
    
      test "image_url" do
        ok = %w{ fred.gif fred.jpg fred.png FRED.JPG FRED.Jpg
                 http://a.b.c/x/y/z/fred.gif }
        bad = %w{ fred.doc fred.gif/more fred.gif.more }
    
        ok.each do |name|
          assert new_product(name).valid?, "#{name} shouldn't be invalid"
        end
    
        bad.each do |name|
          assert new_product(name).invalid?, "#{name} shouldn't be valid"
        end
      end
    end

    执行rails test:models命令,开始执行测试。

    测试功能点4:每件商品的标题具有唯一性

    为了验证这个功能,我们当然可以先创建一个商品并保存它,然后再试图创建一个具有同样标题的商品,来验证这个功能。但是,Rails提供了一个更简单的方法,那就是Rails的fixtures

    第1步:在静态测试文件中编写好静态测试数据
    Rails在创建模型的时候,会在test/fixtures目录下,生成一个“.yml”的静态测试文件。在本例中,这个文件就是“products.yml”。在这个静态测试文件里,有一些YAML格式的静态测试数据,“products.yml”文件的具体内容如下:

    # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
    
    #one:
    #  title: MyString
    #  description: MyText
    #  image_url: MyString
    #  price: 9.99
    #
    #two:
    #  title: MyString
    #  description: MyText
    #  image_url: MyString
    #  price: 9.99
    
    ruby:
      title: Programming Ruby 1.9
      description:
        Ruby is the fastest growing and most exciting dynamic
        language out there. If you need to get working programs
        delivered fast, you should add Ruby to your toolbox.
      price: 49.50
      image_url: ruby.png
    • 每一个静态测试文件中都包含单个模型的测试数据。我们可以将这些测试数据存到该模型对应的数据库表中去,以便在对该模型进行每一项单元测试的时候,数据库表中有现成的测试数据。
    • 静态测试文件的基础名称应该和模型对应的数据库表的名称相匹配。这有助于我们从众多的静态测试文件中,方便地找到哪一个是我们想要使用的静态测试文件;同时,也增加了测试的可读性。例如:在本例中,我们要对Product模型进行单元测试,该模型对应的数据库表的名称是products,所以我们的静态测试文件被Rails自动地命名为了“products.yml”。

    第2步:在单元测试脚本中,通过“fixtures”方法指定用哪个静态测试数据去初始化对应的数据库表,即把准备好的商品信息存到数据库表中去。

    现在,我们要在测试代码test/models/product_test.rb中,用这些静态测试数据去填充products这个数据库表,从而使用这些静态测试数据来对模型Product进行单元测试。

    于是,我们在product_test.rb文件中,用fixtures来指定要使用的静态测试文件,如下所示:

    require 'test_helper'
    
    class ProductTest < ActiveSupport::TestCase
      fixtures :products
      ...
    end

    注意:fixtures :products这条指令,将在进行每一项单元测试前,将products表清空,然后用静态测试文件products.yml里的测试数据去填充products表。

    第3步:使用一个与静态测试文件同名的方法来获取包含了静态测试数据的一个模型对象,然后再创建一个和该对象有着相同标题的新对象

    Rails会自动为每一个静态测试文件定义一个与之同名的方法,将静态测试文件中每一份测试数据的名称(它定义在每一份测试数据的第一行)作为参数,传递给这个方法,就可以获得一个包含了该测试数据的模型对象。
    例如:在下面的代码中,就是将“ruby”这个测试数据的名称作为参数,传递给了“products”方法,从而获得了一个带有静态测试数据的模型对象。

    require 'test_helper'
    
    class ProductTest < ActiveSupport::TestCase
      fixtures :products
    
      test "product is not valid without a unique title" do
        product = Product.new(title: products(:ruby).title,
                              description: "yyy",
                              price: 1,
                              image_url:"fred.gif")  
      end
    end

    第4步:用assert来验证是否能成功创建有同样标题的新对象

    require 'test_helper'
    
    class ProductTest < ActiveSupport::TestCase
      fixtures :products
    
      test "product is not valid without a unique title" do
        product = Product.new(title: products(:ruby).title,
                              description: "yyy",
                              price: 1,
                              image_url:"fred.gif")
    
    »   assert product.invalid?
    »   assert_equal ["has already been taken"], product.errors[:title]
      end
    end

    如果想要避免对抛出的Active Record错误使用硬编码,可以将响应与内置的错误消息表进行比较,来解决这个问题。最终的test/models/product_test.rb文件的代码如下:

    require 'test_helper'
    
    class ProductTest < ActiveSupport::TestCase
      fixtures :products
    
    » test "product is not valid without a unique title -i18n" do
        product = Product.new(title: products(:ruby).title,
                              description: "yyy",
                              price: 1,
                              image_url:"fred.gif")
    
        assert product.invalid?
    »   assert_equal [I18n.translate('errors.messages.taken')],
                     product.errors[:title]
      end
    end

    第5步:执行单元测试测试
    最后,执行rails test:models命令,开始对该功能进行单元测试。

    • 在执行rails test命令后,每一个测试方法都会获得一张被静态测试数据初始化后的数据库表,这是由rails test命令自动完成的,但是也可以单独运行rails db:test:prepare命令来初始数据库表。
    • 在执行rails test命令后,都是在测试数据库中进行测试的。
    展开全文
    heming87 2018-09-10 22:50:15
  • heming87 2018-09-04 21:21:12
  • 149KB weixin_38669628 2019-03-05 01:27:59
  • heming87 2018-09-08 18:42:13
  • 10.17MB jingleizhao 2012-02-01 14:49:37
  • 4.78MB zhuzhenglongfnst 2011-05-18 15:18:30
  • 127B weixin_39840914 2019-07-22 21:47:18
  • 4星
    563KB fqf530854528 2012-07-24 09:00:03
  • 5星
    5.11MB zengjuncsdn 2008-04-25 13:34:19
  • 5星
    123.15MB weixin_42745073 2018-10-20 13:05:56

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,288
精华内容 2,115
关键字:

rails5敏捷开发