`
fantaxy025025
  • 浏览: 1329322 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类

Rails源码阅读(十)在console 使用ActionController::Integration::Session

 
阅读更多

 

Rails源码阅读(十)在console 使用ActionController::Integration::Session

 

ActionController::Integration::Session

在script/console的console_app中,使用的句柄是app,返回ActionController::Integration::Session的一个实例。

 

可以使用的方法1:模拟请求

app的public方法:

delete

delete_via_redirect

follow_redirect!

get

get_via_redirect

head

host!

https!

https?

new

post

post_via_redirect

put

put_via_redirect

redirect?

request_via_redirect

reset!

url_for

xhr

xml_http_request

这些都是模拟http请求的。

例如get方法,模拟get请求,path参数是请求的地址等。

 

    def get(path, parameters = nil, headers = nil)
      process :get, path, parameters, headers
    end

实验:

?> status = app.get '/login'

=> 200

 

process方法代码分析:

          #核心代码
          app = Rack::Lint.new(@application)
          status, headers, body = app.call(env)

从@application是ActionDispatcher的实例可以看出,启动了rack,来处理用户的get post等请求。

这段代码之前主要是rack的准备工作;

这段代码之后的代码在处理rack的返回值工作;

另外,为了配合集成测试,需要在处理请求后,可以做assert操作,这就需要能够得到请求的轨迹,也就是请求了哪个controller,哪个action,request参数,response值等,也就是:

 

          if @controller = ActionController::Base.last_instantiation
            @request = @controller.request
            @response = @controller.response
            @controller.send(:set_test_assigns) #这里使用了module ProcessWithTest
          else
            # Decorate responses from Rack Middleware and Rails Metal
            # as an Response for the purposes of integration testing
            @response = Response.new
            @response.status = status.to_s
            @response.headers.replace(@headers)
            @response.body = @body
          end

          # Decorate the response with the standard behavior of the
          # TestResponse so that things like assert_response can be
          # used in integration tests.
          @response.extend(TestResponseBehavior) #response都加了这些功能

   请求的返回值是:return @status

 

可以使用的方法2: 单元测试

Included Modules包括:

Test::Unit::Assertions

ActionController::TestCase::Assertions

ActionController::TestProcess

这样,可以在app中使用上面3个测试模块的方法。

例如:

app.assert true

app.assert false

实验:

?> app.assert true

=> nil

>> app.assert false

Test::Unit::AssertionFailedError: <false> is not true.

from /opt/ruby/lib/ruby/1.8/test/unit/assertions.rb:48:in `assert_block'

from /opt/ruby/lib/ruby/1.8/test/unit/assertions.rb:500:in `_wrap_assertion'

from /opt/ruby/lib/ruby/1.8/test/unit/assertions.rb:46:in `assert_block'

from /opt/ruby/lib/ruby/1.8/test/unit/assertions.rb:63:in `assert'

from /opt/ruby/lib/ruby/1.8/test/unit/assertions.rb:495:in `_wrap_assertion'

from /opt/ruby/lib/ruby/1.8/test/unit/assertions.rb:61:in `assert'

from (irb):97

from :0

 

可以使用的方法3:命名路由

初始化的源代码:

 

      # Create and initialize a new Session instance.
      def initialize(app = nil)
        @application = app || ActionController::Dispatcher.new
        reset!
      end

 

这里的实例@application是ActionController::Dispatcher的实例,这个实例是rails的入口(详细看前面文)

reset!方法中除了做了些初始化的操作(例如把host设置为"www.example.com"),还包含了命名路由:

 

        unless defined? @named_routes_configured
          # install the named routes in this session instance.
          klass = class << self; self; end #取到单例类
          Routing::Routes.install_helpers(klass) #装载了命名路由

          # the helpers are made protected by default--we make them public for
          # easier access during testing and troubleshooting.
          klass.module_eval { public *Routing::Routes.named_routes.helpers } #!!!
          @named_routes_configured = true 

这样,在console中可以使用命名路由了,当然可以测试。例如:

>> app.login_path

=> "/login"

>> app.login_url

=> "http://www.example.com/login"

注意:

klass = class << self; self; end #注意这句与self.class的区别

klass.module_eval { public *Routing::Routes.named_routes.helpers } #这句真不赖

直接把命名路由弄成了共有方法,详细:

Routing::Routes.named_routes.helpers返回一个Array,*星号的作用是展开作为参数,而public正好接收这些参数,真是个好东西

>> ActionController::Routing::Routes.named_routes.helpers.class

=> Array

 

可以使用的方法4:属性方法

[RW] accept The Accept header to send.

[RW] application Rack application to use

[R] body The body of the last request.

[R] controller A reference to the controller instance used by the last request.

[R] cookies A map of the cookies returned by the last response, and which will be sent with the next request.

[R] headers A map of the headers returned by the last response.

[RW] host The hostname used in the last request.

[R] path The URI of the last request.

[RW] remote_addr The remote_addr used in the last request.

[R] request A reference to the request instance used by the last request.

[RW] request_count A running counter of the number of requests processed.

[R] response A reference to the response instance used by the last request.

[R] status The integer HTTP status code of the last request.

[R] status_message The status message that accompanied the status code of the last request.

例如:

?> app.path

=> "/login"

>> app.remote_addr

=> "127.0.0.1"

如何使用好这些属性和其提供的方法,还要看对每一个对象的了解。

 

可以使用的方法5: ActionController::Base引入的方法

 

  [ControllerCapture, ActionController::ProcessWithTest].each do |mod|
    unless ActionController::Base < mod
      ActionController::Base.class_eval { include mod }
    end
  end
  
其中ControllerCapture,主要作用注释写了已经:
    # A module used to extend ActionController::Base, so that integration tests
    # can capture the controller used to satisfy a request.
    module ControllerCapture #:nodoc:
      def self.included(base)
        base.extend(ClassMethods)
        base.class_eval do
          class << self
            alias_method_chain :new, :capture #重写方法,见下面【1】处调用
          end
        end
      end

      module ClassMethods #:nodoc:
        mattr_accessor :last_instantiation

        def clear_last_instantiation!
          self.last_instantiation = nil
        end

        def new_with_capture(*args)
          controller = new_without_capture(*args) #这里调用了【1】
          self.last_instantiation ||= controller #注意下这里!!!
          controller
        end
      end
    end
用处请看process方法内的一处:
          if @controller = ActionController::Base.last_instantiation
            @request = @controller.request
            @response = @controller.response
            @controller.send(:set_test_assigns)
          else
            # Decorate responses from Rack Middleware and Rails Metal
            # as an Response for the purposes of integration testing
            @response = Response.new
            @response.status = status.to_s
            @response.headers.replace(@headers)
            @response.body = @body
          end
 
ProcessWithTest如下,主要作用就是设置可访问的assigns
  module ProcessWithTest #:nodoc:
    def self.included(base)
      base.class_eval { attr_reader :assigns }
    end

    def process_with_test(*args)
      process(*args).tap { set_test_assigns } #这里用tap方法了
    end

    private
      def set_test_assigns
        @assigns = {}
        (instance_variable_names - self.class.protected_instance_variables).each do |var|
          name, value = var[1..-1], instance_variable_get(var)
          @assigns[name] = value #主要作用就是设置可访问的assigns
          response.template.assigns[name] = value if response
        end
      end
  end

附:
Tap方法:

 

Yields x to the block, and then returns x. The primary purpose of this method is to “tap into” a method chain, in order to perform operations on intermediate results within the chain.

>> (1..10).tap { |x| puts "original: #{x.inspect}" }.to_a.
?>     tap    { |x| puts "array: #{x.inspect}" }.
?>     select { |x| x%2 == 0 }.
?>     tap    { |x| puts "evens: #{x.inspect}" }.
?>     map    { |x| x*x }.
?>     tap    { |x| puts "squares: #{x.inspect}" }
original: 1..10
array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens: [2, 4, 6, 8, 10]
squares: [4, 16, 36, 64, 100]
=> [4, 16, 36, 64, 100]



====完毕====
+
+
+
+




分享到:
评论

相关推荐

    Rails进行敏捷Web开发(所有版本的源码rails3.0-4.0)

    1. Rails 3.0: Rails 3是重大升级,引入了ActionController::Metal,这是一个轻量级的控制器,用于提高性能。同时,它引入了多路由引擎支持,如Rack中间件,使得与其他Web服务器的集成更加容易。此外,ActiveRecord...

    rails-exporter-源码.rar

    《Rails Exporter 源码解析》 Rails Exporter 是一个用于 Rails 应用程序的开源工具,主要用于数据导出功能。源码分析将帮助我们深入理解其内部工作原理,以便更好地利用它来优化我们的应用。 一、Rails 框架基础 ...

    Rails项目源代码

    Ruby on Rails,通常简称为Rails,是一个基于Ruby编程语言的开源Web应用框架,遵循MVC(Model-View-Controller)架构模式。这个“Rails项目源代码”是一个使用Rails构建的图片分享网站的完整源代码,它揭示了如何...

    ruby on rails 教程源码

    Ruby on Rails,简称Rails,是基于Ruby语言的开源Web应用框架,它遵循MVC(Model-View-Controller)架构模式,旨在使开发过程更加简洁高效。这个“ruby on rails 教程源码”很可能是为了辅助学习者深入理解Rails的...

    live-stream:Rails 4 ActionController Live Stream 演示简单的聊天应用程序

    使用 Rails 4 的简单聊天应用程序 - ActionController::Live 应用组件: 1 . 使用 Rails 4 ActionController::Live 的聊天应用程序 2 . 基本 LDAP 身份验证 3 . Redis 服务器集成 4 . 彪马服务器 1 . Rails 4 ...

    rails_console_toolkit:可配置的 Rails 控制台助手

    安装将此行添加到应用程序的 Gemfile 中: gem 'rails_console_toolkit' 然后生成初始化程序: $ bin/rails generate rails_console_toolkit:install或手动编写: # config/initializers/console....

    awesome_rails_console:Rails 控制台增强 - 让你的 Rails 控制台很棒

    awesome_rails_console的优点是: 更少的宝石依赖关系(仅使用除prail-rails和awesome_print之外的rails。其余都是可选的) 更简单的提示修改(类似于你已经熟悉的默认提示) 无需担心配置(因为反正没有太多选择)...

    ActionPack 的 Redis 存储.zip

    ActionPack 的 Redis 存储 redis-actionpack为ActionPack(特别是ActionDispatch )提供会话...对于独立使用ActionController::Base.session_store = :redis_store, servers: %w(redis://localhost:6379/0/session),

    awesome_rails_console, Rails 控制台增强使你的Rails 控制台更加出色.zip

    awesome_rails_console, Rails 控制台增强使你的Rails 控制台更加出色 使你的Rails 控制台非常出色这个 gem 是由使用pry生产,jazz_hands和 jazz_fingers的激发 was 。awesome_rails_console的优点是:减少 gem ...

    基于ruby on rails开发示例源码

    Rails的许多特性,如ActiveRecord(ORM)、ActiveModel、ActionController和ActionView,都是为了支持这种分层架构。 压缩包中的`seanatnci-rails_space-53c56b4`可能是一个具体的Rails项目仓库,包含以下关键组成...

    Rails3常用命令行命令

    Rails3 是 Ruby on Rails 框架的一个版本,它提供了一系列强大的命令行工具,使得开发者可以快速地构建和管理Web应用。在本文中,我们将深入探讨Rails3中的常用命令,帮助你更高效地进行开发工作。 首先,新建一个...

    Rails的精简版本Rails::API.zip

    Rails::API 是 Rails 的精简版本,针对不需要使用完整 Rails 功能的开发者。 Rails::API 移除了 ActionView 和其他一些渲染功能,不关心Web前端的开发者可更容易、快速地开发应用程序,因此运行速度比正常的 Rails ...

    rails 2.2.2 API

    13. **测试(Testing)**:Rails 提供了全面的测试支持,包括单元测试(Test::Unit)、集成测试( ActionController::IntegrationTest)和行为驱动开发(RSpec)。 14. **配置(Configuration)**:Rails 应用可以...

    在Rails中使用SSL

    在Rails中使用SSL(安全套接层)是构建Web应用时确保数据传输安全的重要步骤。Rails框架支持在应用程序中轻松集成SSL,以保护用户敏感信息,如登录凭据和支付详情。以下是一些关于在Rails中实施SSL的关键知识点: 1...

    Agile Web Development with Rails 2nd Edition源码

    源码中的控制器文件演示了如何定义动作,以及如何使用before_action等回调来控制流程。 9. **Testing**: Rails提供了全面的测试框架,包括Unit Test、Integration Test和Feature Test。通过源码,我们可以了解如何...

    Rails上的API:使用Rails构建REST APIAPIs on Rails: Building REST APIs with Rails

    在本篇内容中,我们将深入探讨如何利用Ruby on Rails(简称Rails)这一强大的Web应用程序框架来构建可伸缩且易于维护的RESTful API。Rails以其简洁优雅的语法、高效的开发速度以及良好的社区支持而闻名,这使得它...

    Rails 3 in Action

    《Rails 3 in Action》是2011年由Ryan Bigg撰写的一本关于Ruby on Rails框架的权威指南,专门针对当时最新的Rails 3.1版本进行了深入解析。这本书旨在帮助开发者充分利用Rails 3.1的强大功能,提升Web应用开发的效率...

    Rails相关电子书汇总

    11. **Rails Console**:提供了一个交互式的Ruby环境,便于开发者调试和实验代码。 12. **Rails API模式**:Rails 4引入了API模式,使得构建RESTful JSON接口变得更加简单。 13. **Webpacker和Webpack**:Rails ...

    ruby on rails社区网站开发源码

    在“ruby on rails社区网站开发源码”中,我们可以学习到如何利用Rails构建一个互动性强、功能丰富的社区网站。以下是一些关键知识点: 1. **安装与环境设置**:首先,你需要安装Ruby和Rails。这通常涉及设置Ruby...

    auto-session-timeout:在Rails应用程序中提供自动会话超时

    自动::会话::超时在Rails应用程序中提供自动会话超时。 非常容易安装和配置。... ActionController :: Base auto_session_timeout 1 . hourend 这将使用1个小时的全局超时。 gem假定您的身份验证提供程序具有#

Global site tag (gtag.js) - Google Analytics