技术
就像法国的 火车大维特斯(TGV) (以最高320 km / h的速度行驶)大大减少了现代铁路乘客的旅行时间, 红宝石 on Rails (也称为“ Rails”)大大减少了构建功能强大的Web应用程序所需的时间和精力。 Tim O’Reilly(O’Reilly Media的创始人)将Rails称为突破性技术,Gartner Research在最近的一项研究中指出,许多知名公司正在使用Rails来构建敏捷,可扩展的Web应用程序。
值得注意的是,Rails的普及率很高 超过200,000个网站 目前已使用该技术构建。如今,许多知名公司都在使用Rails来构建敏捷,可扩展的Web应用程序。例子包括Twitter,GitHub,Yammer,Scribd,Groupon,Shopify和Basecamp,仅举几例。
Rails是用Ruby编写的Web应用程序开发框架,它还具有独立于Web服务器的自己的路由系统。 Rails的目标是显着简化Web应用程序的开发,与完成相同任务所需的代码和时间相比,所需的代码和时间更少。
为了实现这一目标,Rails对如何“完成”事情进行了某些假设,然后对其进行相应的设计和结构化。尽管对于那些深深扎根于其他语言和框架的开发人员来说,吸收“世界的全景”有时可能会有点文化冲击,但随着时间的流逝,大多数人会极大地赞赏Rails的方法及其带来的生产力。
挑战
从招聘的角度来看,Rails受欢迎程度的爆炸性增长既是好消息,也有坏消息。一方面,这使Rails开发人员更容易定位,但同时也使寻找顶级珠宝变得更加难以捉摸。
要找到真正的全职或兼职工作的高质量Rails专家,需要高效的招聘流程,如我们的帖子所述 寻找精英人士–寻找并雇用业内最佳开发商。然后,可以通过提出问题(例如此处提出的问题)来扩大此过程,以识别分布在全球的稀疏候选人 真正的Rails专家。找到它们的多种好处可能会在他们能够实现的生产率和结果中实现。
是的,我知道Rails…
Rails简化和简化Web应用程序开发的程度可能会误导新手开发人员低估其功能并过分简化其概念基础。尽管Rails相对易于使用,但绝非简单。
与任何技术一样,知道Rails,然后知道 真的 知道Rails。在寻找真正的语言大师时,我们需要一个面试过程,以准确量化候选人在Rails专业知识连续性中的位置。
为了实现这一目标,本指南提供了一些问题样本,这些问题对于评估候选人对语言的掌握程度和深度至关重要。不过,重要的是要记住,这些示例问题仅旨在作为指导。并非每个值得招聘的“ A”候选人都能正确回答所有问题,也不能全部回答都能保证一个“ A”候选人。归根结底,招聘仍然是一门艺术和一门科学。
经常旅行的旅客?

遇到RoR开发人员的情况并不少见,他们对Rails的基本原理和关键范例的掌握要么很弱,要么有些困惑。
因此,可以帮助评估开发人员对Rails基础的掌握的问题(包括一些更细微的细微差别)是面试过程中的重要组成部分。
这里有些例子:
问:解释Rails请求的处理流程。
在最高级别上,Rails请求通过应用程序服务器提供服务,该服务器负责将传入请求定向到Ruby进程中。使用Rack Web请求界面的流行应用服务器包括 Phusion乘客, 杂种, 瘦, 和 独角兽.
机架解析所有请求参数(以及发布的数据,CGI参数和其他可能有用的信息位)并将其转换为大的 杂凑 (Ruby’s record / dictionary type). This is sometimes called the env
hash, as it contains data about the environment of the web request.
除此请求解析外,Rack是可配置的,允许将某些请求定向到特定的Rack应用。例如,如果要将管理部分中对任何内容的请求重定向到另一个Rails应用程序,则可以在机架级别进行。除了能够在Rails中声明中间件之外,您还可以在此处声明中间件。
这些要求是 不是 定向到其他地方(由您在Rack中定向)定向到您的Rails应用,并在该应用中开始与Rails进行交互 动作分派器,它检查路线。 Rails应用程序可以吐到单独的位置 Rails引擎,然后路由器将请求发送到正确的引擎。 (您也可以在此处将请求重定向到其他与Rack兼容的Web框架。)
一旦进入您的应用程序,便会执行Rails中间件或您的自定义中间件。路由器确定应调用哪种Rails控制器/操作方法来处理请求,实例化适当的控制器对象,执行所有涉及的过滤器,最后调用适当的操作方法。
更多细节 在Rails文档中可用。
问:描述Rails资产管道及其处理资产(例如JavaScript和CSS文件)的方式。
Rails 3.1引入了 资产管道,一种组织和处理前端资产的方法。它提供了导入/请求机制(用于加载相关文件),该机制提供了许多功能。虽然Asset Pipeline确实有其粗糙的优势,但它确实解决了并提供了许多现代的最佳实践,这些实践在HTTP 1.1下提供这些文件。最重要的是,资产管道将:
- 收集,连接和 缩小 每种类型的所有资产都放入一个大文件中
- 使用指纹的版本文件可破坏浏览器缓存中文件的旧版本
资产管道会自动带来Rails选择的 咖啡脚本 由于其JavaScript已预处理/ 转译 选择的语言和 萨斯 作为其CSS翻译语言。但是,作为可扩展框架,它确实允许使用其他编译语言或其他文件源。例如, Rails资产 带给...的力量 凉亭 到您的Rails应用程序,从而允许您管理第三方JavaScript和CSS资产 非常 easily.
问:什么是活动记录,什么是Arel?描述每个功能。
活动记录 在马丁·福勒(Martin Fowler)的书中有描述 企业应用程序架构的模式 作为“在数据库表或视图中包装一行,封装数据库访问并在该数据上添加域逻辑的对象”。
ActiveRecord既是对象关系映射(ORM)设计模式,也是Rails对该设计模式的实现。这意味着与自定义业务逻辑一样,在数据库中获取,查询和存储对象是对象API的一部分。根据他们的喜好和经验水平,开发人员可能会将此视为不希望的副作用或受欢迎的约定。
阿雷尔 提供了ActiveRecord的查询API,允许Ruby on Rails开发专家执行数据库查询,而无需手工编写SQL。 Arel创建了惰性执行的SQL,Rails一直等到最后一秒才将SQL发送到服务器以执行。这使您可以进行Arel查询并向查询中添加另一个SQL条件或排序,直到Rails实际执行查询为止。除非另有说明,否则Arel从其查询返回ActiveRecord对象。
问:什么是约定优于配置模式?提供如何在Rails中应用它的示例。
约定优于配置(CoC) 是一种软件设计模式,只有 非传统的 应用程序的各个方面需要由开发人员指定。当默认约定与所需行为匹配时,将遵循默认行为,而无需任何配置。目的是简化软件开发,而不牺牲过程的灵活性和可定制性。
以下是在Rails中如何应用CoC原则的一些示例:
- 模型和数据库表的命名。 Rails automatically pluralizes class names to find the respective database tables. For a class Book, for example, it will expect a database table named books. For class names composed of multiple words, the model class name should employ CamelCase (e.g.,
BookClub
和 book_clubs
)。
- 主键和外键。 By default, Rails uses an integer column named
id
as the table’s primary key. Foreign key names by default follow the pattern of appending _id
to the singularized tablename (e.g., item_id
for a foreign key into the items
table).
- 保留字用于自动功能。 There are also some optional column names which, if used, automatically add features and functionality to Rails database tables.
created_at
, for example, will automatically be set to the date and time when the record was created. Similarly, updated_at
will automatically be set to the date and time whenever the record was last updated.
- 自动加载类定义。 自动加载是“魔术”,通过它可以从任何地方访问类,而无需明确要求它们。它的工作原理是:当您在代码中引用一个类时,Rails将类名(带有名称空间)作为字符串,调用 下划线 on it, and looks for a file with that name (in all directories specified in your
config.autoload_paths
)。 For example, if you reference a class named FileHandling::ZipHandler
, Rails will automatically search for file_handling/zip_handler.rb
in your config.autoload_paths
. This feature often results in novice Rails programmers thinking that they don’t need to explicitly require referenced classes and that Rails will just auto-magically find them anyway. They then become baffled when they don’t follow this convention and are suddenly being told by Rails that their classes can’t be found.
It is important to note that CoC specifies a default –- but not immutable –- convention. Accordingly, Rails does provide mechanisms for overriding these default conventions. As an example, the default database table naming scheme mentioned above can be overridden by specifying the ActiveRecord::Base.table_name
as shown here:
class Product < ActiveRecord::Base
self.table_name = "LEGACY_PRODUCT_TABLE"
end
问:什么是“胖模型,瘦控制器”方法?讨论它的一些优点和陷阱以及一些替代方法。
“胖模型瘦控制器”是基于MVC的Rails设计模式。
MVC本身是一种软件设计模式,可以将系统分为三个独立的层次。即模型,视图和控制器。 MVC努力通过明确定义的API来确保其各层之间的干净隔离。在设计良好的MVC系统中,这些API充当了牢固的边界,有助于避免在MVC逻辑上不同的子系统之间扩展实现的“触角”。
“胖模型瘦控制器”设计模式提倡在模型中放置尽可能多的逻辑,以实现(a)最大复用率和(b)易于测试的代码。
That said, a common pitfall for Rails developers is to end up with “overly bloated” models by adhering too blindly to the “fat model, skinny controller” paradigm. The infamous User model is a prime example of this. Since many Rails apps are about the user entering data into the system, or sharing information with their friends socially, the user model will often gain more and more methods, eventually reaching the point where the user.rb
model becomes bulky and unmanageable in size.
一些值得考虑的关键替代方案包括:
- 使用其他对象:将功能从模型中提取到其他对象(例如Decorators或Service对象)中
- Rails的六角形架构:采用六边形架构,将应用程序视为六边形,六边形的每一面代表应用程序需要的某种外部交互。
- DCI(数据上下文交互):不关注单个对象,而是关注数据与其上下文之间的通信和交互。
问:请描述Rails的测试原理。
Rails从框架的开始就内置了测试支持,并且它已成为文化的一部分。结果,有大量工具可用于在Rails环境中进行测试。
默认情况下,Rails 4.0+使用 迷你测试 Ruby标准库测试框架。
在Rails项目中有明确定义的位置,用于每个层(模型,控制器,布线,视图,模型)的测试以及集成测试。由于Rails的MVC基础,通常可以在不依赖其他层的情况下对这些层(集成测试除外)进行测试。
例如,我们可以在测试运行之前创建数据库记录,其中包含我们希望测试返回的属性。我们的测试可以通过检查是否返回了我们在上面创建的对象来确保期望,我们的show post controller动作可以确保检索到我们想要的帖子。如果不是,则出了点问题,否则我们的代码必须存在错误。这是此类测试的示例:
class PostsControllerTest < ActionController::TestCase
setup do
@post = posts(:one)
end
test "should show post" do
get :show, id: @post
assert_response :success
end
end
集成测试(通常称为功能测试)通常会使用以下测试工具来驱动应用程序,就像用户单击按钮一样 水豚 (可以以多种方式模拟用户操作,包括嵌入式驱动 WebKit,或使用 硒)。
虽然MiniTest是现成的Rails标准,但您经常会看到 规范 代替宝石。这提供了一种用于测试的领域特定语言,该语言可能比MiniTest更自然地阅读。
一些Rails项目使用 黄瓜测试框架 用简单的英语句子描述软件行为。与现场客户或专用的质量检查资源协作时,这通常很有用。在理想的情况下,这些非开发人员可以编写自动化集成测试,而无需查看一行Ruby代码。
在轨道上
可以期望与Rails进行过广泛合作的人对其功能,构造和特质非常熟悉。这些问题说明了衡量这种专业知识的程度和深度的方法。
Q: Explain the use of yield
和 content_for
in layouts. Provide examples.
yield
identifies where content from the view should be inserted. The simplest approach is to have a single yield
, into which the entire contents of the view currently being rendered is inserted, as follows:
<html>
<head>
</head>
<body>
<%= yield %>
</body>
</html>
您还可以创建具有多个屈服区域的布局:
<html>
<head>
<%= yield :head %>
</head>
<body>
<%= yield %>
</body>
</html>
The main body of the view will always render into the unnamed yield
. To render content into a named yield
, use the content_for
method. content_for
allows for insertion of content into a named yield
block in a layout. This can be helpful with layouts that contain distinct regions, such as sidebars and footers, into which distinct blocks of content are to be inserted. It can also be useful for inserting tags that load page-specific JavaScript or CSS files into the header of an otherwise generic layout.
Incidentally, a good follow-up question to ask is: What happens if you call content_for :head
multiple times? The answer is that all of the values get concatenated.
问:什么是N + 1查询,如何避免它们?
考虑以下代码,该代码找到10个客户并打印其邮政编码:
clients = Client.limit(10)
clients.each do |client|
puts client.address.postcode
end
该代码实际上执行11个查询; 1(查找10个客户端),然后再添加10个(每个客户端一个,以加载其地址)。这被称为“ N + 1查询”(在此示例中,N为10)。
渴望加载 is the mechanism for loading the associated records of the objects returned by Model.find
使用 as few queries as possible.
活动记录的急切加载功能使您可以通过指定来显着减少查询数量 提前 all the associations that are going to be loaded. This is done by calling the includes
(or preload
) method on the Arel (ActiveRecord::Relation
) object being built. With includes, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.
We could therefore rewrite the above code to use the includes
method as follows:
clients = Client.includes(:address).limit(10)
clients.each do |client|
puts client.address.postcode
end
由于急切的加载,此代码的修订版将仅执行2个查询,而原始版本中仅执行11个查询。
问:Rails中的“过滤器”是什么?描述三种类型的过滤器,包括如何以及为什么使用每种过滤器,以及它们的执行顺序。提供示例。
筛选器 本质上是在控制器操作之前,之后或“周围”运行的回调方法:
- 之前的过滤方法 在控制器动作之前运行,因此可能会中断请求周期。常见的之前过滤器是一种要求用户登录才能执行操作的过滤器。
- 后过滤方法 在控制器操作之后运行,因此无法停止执行该操作,但是可以访问将要发送到客户端的响应数据。
- 周围过滤方法 被“包裹”在控制器动作上。因此,他们可以控制动作的执行以及在执行动作之前和/或之后执行代码。
例如,在更改具有批准工作流程的网站中,管理员可以使用“周围”过滤器轻松地预览更改,如下所示:
class ChangesController < ApplicationController
around_action :wrap_in_transaction, only: :show
private
def wrap_in_transaction
ActiveRecord::Base.transaction do
begin
yield
ensure
raise ActiveRecord::Rollback
end
end
end
end
请注意,周围过滤器还会包装渲染。 特别地,在以上示例中,如果视图(例如,通过范围)从数据库读取,则它将在事务内进行读取,并因此呈现数据以进行预览。您也可以选择不自行产生和构建响应,在这种情况下,将不执行操作。
执行的顺序有些棘手,并且很容易理解。筛选器方法按以下顺序执行:
- 在过滤方法之前,按定义顺序。
- 围绕过滤器方法,按定义顺序排列。
- 过滤方法后,按相反顺序。
另外,由于Ruby实例化类的方式,父类的filter方法将运行 前 它的子类的那些。
问:什么是Rack中间件?它与控制器过滤器/动作相比如何?
克里斯蒂安·纽基兴(Christian Neukirchen)在2007年发布 架子,这是用于在Ruby中处理Web请求的模块化标准接口。机架类似于其他语言中的其他类似机制,例如 WSGI 在Python方面,或者 Java Servlet或Microsoft的 Internet服务器应用程序编程接口(ISAPI).
在您的Rails操作方法处理请求之前,它们将通过Rails或开发人员声明的各种Rack中间件功能。机架中间件通常用于执行功能,例如请求清除,安全措施,用户授权或配置文件。
You can see a list of available middleware components (both developer defined and those defined by Rails) by running rake middleware
on the command line.
架子中间件和过滤器之间的主要区别是Rack中间件称为 前 Rails进行路由和调度,而过滤器被调用 后 this routing has occurred (i.e., when Rails is about to call your controller action method). As such, its is advantageous to filter out requests to be ignored in middleware whenever possible, such as requests from common attack URLs (phpadmin.php
requests, for example, can be discarded in middleware, as they will never resolve in a Rails app and is probably just some attempt to hack the site.)
问:请说明什么是Rails的批量分配漏洞以及Rails的控制现场访问的方法。
When the user performs a post (such as, for example, creating a new User
) Rails needs to save all that new data into the database. This data is accessible from your Rails action via the params
Hash.
由于Web应用程序涉及更新/保存用户更改的每个字段,因此Rails提供了一些方便的方法来处理此问题,称为批量分配帮助器。
For example, prior to Rails 4, creating a new User
object with parameters from a submitted form looked like:
User.create(params[:user])
params[:user]
will contain keys for the elements the user entered on the form. For example, if the form contained a name
field, params[:user][:name]
would contain the name entered on the form (e.g., “Jeff Smith”).
Convention vs. configuration strikes again here: name
is the name of both the input element in the form 和 数据库中列的名称。
In addition to the create
method, you can update a record the same way:
@user = User.find(params[:id])
@user.update_attributes(params[:user])
But what happens when a hacker goes in and edits your HTML form to add new fields? They may, for example, guess that you have an is_admin
field, and add it to the HTML form field themselves. Which now means that – even though you didn’t include it on the form that’s served to users – your hacker has gone in and made themselves an admin on your site!
这称为 大规模分配漏洞;即,为所有这些字段分配未过滤的所有内容,只是相信唯一的字段名称和值将是在HTML表单上合法的字段名称和值。
Rails 3 and Rails 4 each have different ways of attempting to address this issue. Rails 3 attempted to address it via attr_protected
/ attr_accessible
controls at the model level, while Rails 4 addresses it via strong parameters and a filtering mechanism at the controller level. Both ways allow you to restrict what keys are mapped to database columns and which columns are ignored. Using these mechanisms, in the prior is_admin
example, you can set the is_admin
field to only change when code explicitly modifies the field value, or only allow it to be changed in certain situations.
大图景
对Rails的专业知识远远超出了该语言的技术细节。 Rails专家将对其好处和局限性有深入的了解和欣赏。因此,这里有一些示例问题可以帮助评估候选人专业知识的这一方面。
问:为什么有人说“铁轨无法扩展”?
推特是最早使用Rails的知名网站之一。在大约2006-2008年的时间范围内,Twitter的增长率使服务器错误(“失败的鲸鱼”)对用户来说非常普遍,促使用户和技术专家将责任推到了Rails的脚上。就像任何软件一样,可伸缩性问题的原因可能是复杂且多方面的。因此,并不是所有Twitter的扩展问题都可以说是特定于Rails的。但是,重要的是要了解Rails在哪里遇到了可伸缩性问题以及如何解决或可以解决这些问题。
自从Twitter出现Rails缩放问题以来,Ruby生态系统已经得到改善,例如,MRI Ruby(核心和主要的Ruby实现)中使用了更好的内存管理技术。
现代Rails应用程序通常通过以下一种或多种方式缓解扩展问题:
- 实施缓存解决方案(Rails 4在此引入了不错的进步)
- 利用内置的自动扩展功能来利用(或实施)服务器或平台解决方案
- 分析昂贵的操作,并将其移出Ruby或一个整体式Rails应用程序
- 将某些操作放在后台/工作人员队列中,以在以后完成(例如,异步执行导出操作,导出完成时通过电子邮件向用户发送下载链接通知)
传统上,网站和RoR应用程序之间是一对一的映射(即,一个网站=一个Rails应用程序),但越来越多的趋势转向 面向服务的架构(SOA) 一种将应用程序性能关键部分拆分为新的/单独的应用程序的方法,主应用程序通常通过网络服务调用与之通信。这种方法有很多优点。也许最值得注意的是,这些独立的服务可以酌情采用替代技术。这可能是Ruby中的轻量级/响应速度更快的解决方案,或者是用编写的服务 斯卡拉 (例如Twitter),或者 Node.js, Clojure, 或者 去.
但是编写单独的服务并不是加速Rails应用的唯一方法。例如,Github有一个有趣的 文章 关于如何配置Rails并最终实现了一组C api,以在网络上执行文本转义。
问:Rails什么时候是项目的理想选择?
Rails是一个自以为是的框架,它是最迷人或令人沮丧的属性之一,具体取决于您问谁。 Rails已经对视图模板引擎,对象角色模型(ORM)以及路由如何转换为动作进行了(默认但可配置)选择。
这些选择的结果是,Rails是一个项目的绝佳选择,在该项目中,您的应用程序可以完全控制自己的数据库,大部分返回HTML(或者至少不仅仅返回JSON),并且在大多数情况下将数据显示回用户始终使用它的存储方式。
因为Rails是可配置的,所以如果您 想 可以偏离Rails规范,但这通常要付出工程成本。是否想连接到现有的MS SQL数据库?您可以这样做,但在此过程中会遇到一些困难。是否想用Rails构建一个单页应用程序,并返回大部分JSON对象?您会发现Rails对您的帮助不尽如您接受/响应HTML格式一样。
问:Rails有哪些缺点?
Rails通常用于包含几百行代码的代码库,并且主要用于其自己的数据库对象。如果您要编写只执行计算的Web服务(“现在就给我华氏温度”),Rails会添加许多您可能不需要的支撑结构“过大杀伤力”。
另外,Rail的配置约定也使它有时不适用于必须与另一方控制的数据库模式进行交互的情况。而且,基于Ruby的解决方案在Windows企业环境中可能很难卖,因为Ruby对Windows的支持不如对Unix的支持。
与Python一样,默认Ruby实现中的并发故事(核磁共振;全局解释器锁(GIL)在某种程度上阻碍了CRuby的发展,从广义上讲,这意味着一次只有一个线程可以执行Ruby代码。 (红宝石 和 鲁比尼乌斯,其他Ruby实现没有GIL。
基于Ruby的实现也可能不是最适合需要异步解决方案的问题的(例如,从多个API提取数据以执行聚合计算,与社交媒体API交互或响应可能会收到数千个小请求的情况)一分钟)。
话虽如此,但是有一些工具可以在Ruby中实现基于异步回调的模式(例如 EventMachine),或使用Actor并发模型(赛璐珞)。当然,如果您的问题适合该领域,则可以使用多种后台工作人员机制。
最后是Ruby Rookie还是宝石学家?
出色的Rails开发人员要求您成为以下方面的专家: 红宝石 编程语言。因此,这里有一些问题可以帮助评估候选人专业知识的这一方面。
问:什么是Ruby mixins,它们如何工作,以及您将如何使用它们?使用它们有哪些优点?潜在的问题是什么?举例说明您的答案。
“混合”是Ruby中用于另一个类中包含的模块的术语。当一个类包含一个模块时,它由此“混合”(即合并)其所有方法和常量。如果一个类包含多个模块,则它将包含所有这些模块的方法和常量。 因此,尽管Ruby不正式支持多重继承,但是mixins提供了一种机制,通过该机制可以很大程度上实现或至少近似地实现多重继承。 (可以期望有经验的候选人在讨论Ruby mixins时提及多重继承。)
在内部,Ruby通过将模块插入类的继承链中来实现mixin(因此mixin实际上通过Ruby中的继承工作)。
考虑以下简单示例:
module Student
def gpa
# ...
end
end
class DoctoralStudent
include Student
def thesis
# ...
end
end
phd = DoctoralStudent.new
In this example, the methods of the Student
class are incorporated into DoctoralStudent
class, so the phd
object supports the gpa
method.
It is important to note that, in Ruby, the require
statement is the logical equivalent of the include
statement in other languages. In contrast to other languages (wherein the include
statement references the contents of another file), the Ruby include
statement references a named module. Therefore:
- The module referenced by an
include
statement may either be in the same file (as the class that is including it) or in a different file. If in a different file, a require
statement must also be used to properly incorporate the contents of that file.
- A Ruby
include
makes a reference from the class to the included module. As a result, if the definition of a method in the included module is modified, even at runtime, all classes that include that module will exhibit the new behavior when that method is invoked.
mixin的优点不容忽视,它们也不乏缺点,因此应谨慎使用。一些 潜在的陷阱 include:
- 实例变量名称冲突。 不同的mixin可能使用具有相同名称的实例变量,并且如果包含在相同的类中,则它们可能在运行时产生无法解决的冲突。
- 静默覆盖方法。 在其他语言中,两次定义某些内容将导致错误消息。在Ruby中,如果一个方法定义了两次,则第二个定义将简单地(且无声地!)覆盖第一个定义。因此,在Ruby中跨多个mixins的方法名称冲突不是简单的错误,而是会引入难以捉摸的粗糙错误。
- 类膨胀。 mixins的易用性也可能导致它们的“滥用”。一个很好的例子是一个类,其中mixins太多了,因此在公众中占有很大的份额。耦合和凝聚力规则开始发挥作用,最终您可以得到一个系统,在该系统中,经常包含的模块更改可能会造成灾难性的影响。传统的继承或组成更不容易出现这种肿。通常,将类的各个部分提取到混合在一起的模块中,类似于将乱七八糟的东西放进大垃圾箱中来打扫房间。在您开始打开垃圾箱之前,它看起来很干净。
问:比较和对比Ruby中的符号和字符串?为什么要使用一个与另一个?
符号是基于值和不可变对象的单例。与字符串不同 并非所有符号 可能被垃圾收集了。
另一方面,即使系统共享对象,字符串也可以创建多个对象,即使它们共享一个值,也是可变的并且被垃圾回收。
由于符号是基于值的单例(即使在程序中多次出现,一个值也只有一个符号对象),因此比较两个符号是否相同很简单(Ruby基本上只需要比较它们的object_id即可)值)。因此,符号最常用作哈希键,许多库都期望带有特定符号键的选项散列。
可以通过冻结方法使字符串不可变(“冻结”)。但是,尽管这会改变字符串的一种行为,但是创建两个具有相同值的冻结字符串仍然会导致两个字符串对象。当您使用Symbol时,Ruby将首先检查字典,如果找到字典,将使用该Symbol。如果在词典中未找到符号,则解释器将实例化一个新的符号并将其放入堆中。
如中所述 红宝石编程语言 O’Reilly的书(由Matz和Flanigan撰写):
红宝石解释器的一种典型实现是维护一个符号表,在其中存储它知道的所有类,方法和变量的名称。这样一来,这样的解释器就可以避免大多数字符串比较:它例如通过方法名称在符号表中的位置来引用方法名称。这将相对昂贵的字符串运算转换为相对廉价的整数运算。
在Ruby中,符号也很普遍(主要是哈希键和方法名;在Ruby 2.1之前的版本中,它们还用作准关键字参数和穷人常量)。由于其性能,内存和使用方面的考虑,符号最常用作哈希键,许多库都期望选项哈希具有特定的键符号。
与字符串不同(与任何其他变量一样,都是垃圾回收),符号在程序执行过程中绝不会被垃圾回收。
由于字符串和符号是不同的对象,因此以下示例经常使经验不足的Ruby程序员不知道。
例如,考虑以下哈希:
irb(main):001:0> a = {:key => 1}
irb(main):002:0> puts a['key']
=> nil.
You may be expecting to see 1
printed here, especially if a
was defined elsewhere in your program. But, as strings and symbols are different; i.e., key
(the symbol) and 'key'
(the string) are not equivalent. Accordingly, Ruby correctly returns nil
for a['key']
(even though this is annoying for the unsuspecting programmer wondering where her value is!)
Rails has a class, 杂凑WithIndifferentAccess
, which acts like a Hash object, except it treats strings and symbols with the same values as equivalent when used as key names, thereby avoiding the above issue:
irb(main):001:0> a = HashWithIndifferentAccess.new({:key => 1})
irb(main):002:0> puts a['key']
=> 1
有一个重要的警告。考虑以下控制器操作:
def check_value
valid_values = [:bad, :ok, :excellent]
render json: valid_values.include?(params[:value].to_sym)
end
这种看起来很天真的代码实际上是拒绝服务(DOS)攻击漏洞。 由于永远无法收集符号(并且由于这里我们将用户输入转换为符号),因此用户可以继续为该端点提供唯一值,并且最终将耗尽足够的内存以使服务器崩溃,或者至少将其带入服务器。嘎然而止。
问:描述在Ruby中定义实例方法的多种方法。
实例方法当然可以定义为类定义的一部分。但由于Ruby支持 元编程 (这意味着Ruby代码可以自我修改),Ruby程序还可以在运行时将方法添加到现有类中。因此,有多种用于在Ruby中定义方法的技术,如下所示:
(1) Within a class definition, using def
(The simplest answer)
class MyObject
def my_method
puts "hi"
end
end
这是定义类的实例方法的标准方法。
(2)在类定义中, 没有 使用 def
class MyObject
define_method :my_method do
puts "hi"
end
end
Since define_method
is executed when Ruby instantiates the MyObject
class object, you can do any kind of dynamic code running here. For example, here’s some code that only creates our method if it’s being run on a Monday:
require 'date'
class MyObject
if Date.today.monday?
define_method :my_method do
puts "Someone has a case of the Mondays"
end
end
end
Executing MyObject.new.my_method
on any other day of the week will give us an exception about no such method existing. Which is true: it’ll only exist on Mondays!
(It’s important to note that classes are objects too in Ruby, so our MyObject
class is an instantiation of a Class
object, just like in a = MyObject.new
, a
is an instance of MyObject
.)
(3)扩展现有的类定义
红宝石还允许扩展类定义。例如:
class MyObject
def say_hello
puts "hey there!"
end
end
class MyObject
def say_goodbye
puts "buh-bye"
end
end
The above code will result in the MyObject
class having both the say_hello
和 the say_goodbye
methods defined.
Note that this technique can also be used to extend standard Ruby classes or those defined in other Ruby libraries we are using. For example, here we add a squawk
method to the standard Ruby string class:
class String
def squawk
puts "SQUAWK!!!"
end
end
"hello".squawk
(4)使用 class_eval
class_eval
动态评估指定的字符串或代码块,因此可用于向类添加方法。
For example, we can define the class MyObject
:
class MyObject
...
end
… and then come back at a later time and run some code to dynamically add my_method
to the MyObject
class:
MyObject.class_eval do
def my_method
puts "hi"
end
end
(5)使用 method missing
红宝石还提供了一个钩子来检查未定义的方法。如果尚未定义方法,则可以用来动态添加方法。例如:
class MyObect
def method_missing(method_name_as_symbol, *params)
if method_name_as_symbol == :my_method
puts "hi"
end
end
end
包起来
红宝石 on Rails是用于快速Web开发的强大框架。尽管所有开发人员都可以像使用任何技术一样从其易用性和灵活性中受益,但真正掌握了该技术和开发过程的人将意识到其使用的最大潜力和生产力。
尽管没有像这样的简要指南可以完全涵盖在招聘RoR开发人员的采访中涵盖的技术主题的广度和深度,但此处提供的问题为识别在Rails框架中拥有扎实且有原则基础的人员提供了有效的基础。它的范例。