Ruby on Rails 3.1 Release Notes

Ruby on Rails 3.1 Release Notes

Highlights in Rails 3.1:

Rails中的亮点:

  • Streaming
  • Reversible Migrations 可逆(数据)迁移
  • Assets Pipeline Assets管道
  • jQuery as the default JavaScript library jQuery作为默认的 JavaScript library

This release notes cover the major changes, but don’t include every little bug fix and change. If you want to see everything, check out the listofcommits in the main Rails repository on GitHub.

这次发行notes涵盖了主要的changes,但是没有包含每个很littlebug修复和chage。如果你希望看到所有的事情,检查Rails GitHub主代码仓库中的listofcommits

1 Upgrading to Rails 3.1升级到Rails 3.1

If you’re upgrading an existing application, it’s a great idea to have good test coverage before going in. You should also first upgrade to Rails 3 in case you haven’t and make sure your application still runs as expected before attempting to update to Rails 3.1. Then take heed of the following changes:

如果你打算升级一个存在的应用程序,在开始进入升级的时候有一个很好的测试覆盖是一个好主意。你还应该首先升级到Rails 3以防止你并没有确保你的应用程序在企图升级到Rails 3.1之前能够预计到升级后仍然能够运行。然后留意随后(介绍)的changes

1.1 Rails 3.1 requires at least Ruby 1.8.7

Rails 3.1 requires Ruby 1.8.7 or higher. Support for all of the previous Ruby versions has been dropped officially and you should upgrade as early as possible. Rails 3.1 is also compatible with Ruby 1.9.2.

Rails 3.1需要至少Ruby 1.8.7或者更高。曾经支持的所有的早先的Ruby版本被正式取消,你需要尽快升级。Rails 3.1同时也与Ruby 1.9.2兼容。

Note that Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterprise Edition have these fixed since release 1.8.7-2010.02 though. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults, so if you want to use 1.9.x jump on 1.9.2 for smooth sailing.

注意Ruby 1.8.7 p248p249marshaling bugs其与Rails冲突。Ruby企业版自1.8.7-2010.02 发行版已经修复了这些bug。在以1.9开头的rubyRuby 1.9.1是不可用的因为it outright segfaults,因此如果你想使用1.9.x可以平稳的跳至1.9.2

2 Creating a Rails 3.1 application

# You should have the ‘rails’ rubygem installed

$ rails new myapp

$ cd myapp

2.1 Vendoring Gems

Rails now uses a Gemfile in the application root to determine the gems you require for your application to start. This Gemfile is processed by the Bundler gem, which then installs all your dependencies. It can even install all the dependencies locally to your application so that it doesn’t depend on the system gems.

Rails现在使用一个位于应用程序根目录的Gemfile文件来决定使你开始你的应用程序的require。这个Gemfile文件被Bundler gem加工生成,它会随后安装你所有的依赖。它甚至可以以你的应用程序为locally安装依赖,使得你的应用程序不用依赖系统gems

 

vendor/ A place for all third-party code. In a typical Rails application, this includes Ruby Gems, the Rails source code (if you install it into your project) and plugins containing additional prepackaged functionality.放置第三方代码的地方。在一个典型的Rails应用程序中,这里包含Ruby GemsRails源代码(如果你把Rails安装到你的项目中)还包含一些预先包装好的额外的插件

More information: – bundlerhomepage

2.2 Living on the Edge

Bundler and Gemfile makes freezing your Rails application easy as pie with the new dedicated bundle command. If you want to bundle straight from the Git repository, you can pass the --edge flag:

BundlerGemfile通过新的专用bundle 命令来冻结你的应用程序就像吃馅饼一样简单。如果你想直接从Git仓库bundle,你可以通过edge flag

$ rails new myapp –edge

If you have a local checkout of the Rails repository and want to generate an application using that, you can pass the --dev flag:

如果你有一个从Rails源代码仓库checkout的本地Rails并且你想生成一个应用程序使用(上面的方法)你可以通过dev 标志:

$ ruby /path/to/rails/bin/rails new myapp –dev

3 Rails Architectural建筑的Changes

3.1 Assets Pipeline

The major change in Rails 3.1 is the Assets Pipeline. It makes CSS and JavaScript first-class code citizens and enables proper organization, including use in plugins and engines.

Rails 3.1中主要的更改就是Assets Pipeline(管道)。它使得CSSJavaScript 一流的代码公民可以合适的组织他们,包含使用pluginisengines

The assets pipeline is powered by Sprockets and is covered in the AssetPipeline guide.

3.2 HTTP Streaming

HTTP Streaming is another change that is new in Rails 3.1. This lets the browser download your stylesheets and JavaScript files while the server is still generating the response. This requires Ruby 1.9.2, is opt-in and requires support from the web server as well, but the popular combo of nginx and unicorn is ready to take advantage of it.

HTTP StreamingRails 3.1另一更改。这使得浏览器下载你的stylesheetsJavaSript文件即使服务器仍然在响应。这需要Ruby 1.9.2,它是需要从服务器中选择以及服务器同样支持HTTP Streaming,但是受欢迎的nginxunicom组织已经准备advantage HTTP Streaming

3.3 Default JS library is now jQuery

jQuery is the default JavaScript library that ships with Rails 3.1. But if you use Prototype, it’s simple to switch.

Jquey是默认的JavaScript library搭载在Rrails 3.1.但是如果你使用Prototype,它更改很简单。

$ rails new myapp -j prototype

3.4 Identity Map 身份map

Active Record has an Identity Map in Rails 3.1. An identity map keeps previously instantiated records and returns the object associated with the record if accessed again. The identity map is created on a per-request basis and is flushed at request completion.

Rails 3.1Active Record有一个Indentity Map。一个identity map保留先前的实例化的记录并且如果再次访问返回记录的对象的关系。Indentity map是基于每个请求创建的并且在请求完成刷新。

Rails 3.1 comes with the identity map turned off by default.

Rails 3.1默认Identity map是关闭的。

4 Railties

  • jQuery is the new default JavaScript library.

Jquey是新的默认的JavaScript library

  • jQuery and Prototype are no longer vendored and is provided from now on by the jquery-rails and prototype-rails gems.

jQueyPrototype不再vendored并且从现在开始提供的是jquery-rails and prototype-rails gems

  • The application generator accepts an option -j which can be an arbitrary string. If passed “foo”, the gem “foo-rails” is added to the Gemfile, and the application JavaScript manifest requires “foo” and “foo_ujs”. Currently only “prototype-rails” and “jquery-rails” exist and provide those files via the asset pipeline.

应用程序创建器接受一个选项-j其可以是任意字符串。如果传递foo”gem “foo-rails”就被添加到Gemfile,并且应用程序的JavaScript manifest requires “foo” and “foo_ujs”。当前只有prototype-rails” and “jquery-rails”存在并且通过asset pipeline提供这些文件。

  • Generating an application or a plugin runs bundle install unless --skip-gemfile or --skip-bundle is specified.

生成一个应用程序或者一个plugin运行bundle install除非–skip-gemfile或者–skip-bundle被指定

  • The controller and resource generators will now automatically produce asset stubs (this can be turned off with --skip-assets). These stubs will use CoffeeScript and Sass, if those libraries are available.

Controllerresource创建器将会自动的产生asset stubs(this can be turned off with --skip-assets)。这些stub将会使用CoffeeScript and Sass,如果这些libraries是可用的。

  • Scaffold and app generators use the Ruby 1.9 style hash when running on Ruby 1.9. To generate old style hash, --old-style-hash can be passed.
  • Scaffold controller generator creates format block for JSON instead of XML.
  • Active Record logging is directed to STDOUT and shown inline in the console.
  • Added config.force_ssl configuration which loads Rack::SSL middleware and force all requests to be under HTTPS protocol.
  • Added rails plugin new command which generates a Rails plugin with gemspec, tests and a dummy application for testing.
  • Added Rack::Etag and Rack::ConditionalGet to the default middleware stack.
  • Added Rack::Cache to the default middleware stack.
  • Engines received a major update – You can mount them at any path, enable assets, run generators etc.

5 Action Pack

5.1 Action Controller

  • A warning is given out if the CSRF token authenticity cannot be verified.
  • Specify force_ssl in a controller to force the browser to transfer data via HTTPS protocol on that particular controller. To limit to specific actions, :only or :except can be used.
  • Sensitive query string parameters specified in config.filter_parameters will now be filtered out from the request paths in the log.
  • URL parameters which return nil for to_param are now removed from the query string.
  • Added ActionController::ParamsWrapper to wrap parameters into a nested hash, and will be turned on for JSON request in new applications by default. This can be customized in config/initializers/wrap_parameters.rb.
  • Added config.action_controller.include_all_helpers. By default helper :all is done in ActionController::Base, which includes all the helpers by default. Setting include_all_helpers to false will result in including only application_helper and the helper corresponding to controller (like foo_helper for foo_controller).
  • url_for and named url helpers now accept :subdomain and :domain as options.
  • Added Base.http_basic_authenticate_with to do simple http basic authentication with a single class method call.

class PostsController < ApplicationController

USER_NAME, PASSWORD = “dhh”, “secret”

 

before_filter :authenticate, :except => [ :index ]

 

def index

render :text => “Everyone can see me!”

end

 

def edit

render :text => “I’m only accessible if you know the password”

end

 

private

def authenticate

authenticate_or_request_with_http_basic do |user_name, password|

user_name == USER_NAME && password == PASSWORD

end

end

end

..can now be written as

class PostsController < ApplicationController

http_basic_authenticate_with :name => “dhh”, :password => “secret”, :except => :index

 

def index

render :text => “Everyone can see me!”

end

 

def edit

render :text => “I’m only accessible if you know the password”

end

end

Added streaming support, you can enable it with:

class PostsController < ActionController::Base

stream

end

You can restrict限制it to some actions by using :only or :except. Please read the docs at ActionController::Streaming for more information.

  • The redirect route method now also accepts a hash of options which will only change the parts of the url in question, or an object which responds to call, allowing for redirects to be reused.

5.2 Action Dispatch

  • config.action_dispatch.x_sendfile_header now defaults to nil and config/environments/production.rb doesn’t set any particular value for it. This allows servers to set it through X-Sendfile-Type.
  • ActionDispatch::MiddlewareStack now uses composition组成over inheritance and is no longer an array.
  • Added ActionDispatch::Request.ignore_accept_header to ignore accept headers.
  • Added Rack::Cache to the default stack.
  • Moved etag responsibility from ActionDispatch::Response to the middleware stack.
  • Rely on Rack::Session stores API for more compatibility across the Ruby world. This is backwards incompatible since Rack::Session expects #get_session to accept four arguments and requires #destroy_session instead of simply #destroy.
  • Template lookup now searches further up in the inheritance chain.

5.3 Action View

  • Added an :authenticity_token option to form_tag for custom handling or to omit the token by passing :authenticity_token => false.
  • Created ActionView::Renderer and specified an API for ActionView::Context.
  • In place SafeBuffer mutation is prohibited禁止in Rails 3.1.
  • Added HTML5 button_tag helper.
  • file_field automatically adds :multipart => true to the enclosing form.
  • Added a convenience idiom to generate HTML5 data-* attributes in tag helpers from a :data hash of options:

tag(“div”, :data => {:name => ‘Stephen’, :city_state => %w(Chicago IL)})

# => <div data-name=”Stephen” data-city-state=”[&quot;Chicago&quot;,&quot;IL&quot;]” />

Keys are dasherized. Values are JSON-encoded, except for strings and symbols.

  • csrf_meta_tag is renamed to csrf_meta_tags and aliases csrf_meta_tag for backwards compatibility.
  • The old template handler API is deprecated and the new API simply requires a template handler to respond to call.
  • rhtml and rxml are finally removed as template handlers.
  • config.action_view.cache_template_loading is brought back which allows to decide whether templates should be cached or not.
  • The submit form helper does not generate an id “object_name_id” anymore.
  • Allows FormHelper#form_for to specify the :method as a direct option instead of through the :html hash. form_for(@post, remote: true, method: :delete) instead of form_for(@post, remote: true, html: { method: :delete }).
  • Provided JavaScriptHelper#j() as an alias for JavaScriptHelper#escape_javascript(). This supersedes the Object#j() method that the JSON gem adds within templates using the JavaScriptHelper.
  • Allows AM/PM format in datetime selectors.

6 Active Record

  • Added a class method pluralize_table_names to singularize/pluralize复数table names of individual models. Previously this could only be set globally for all models through ActiveRecord::Base.pluralize_table_names.

class User < ActiveRecord::Base

self.pluralize_table_names = false

end

  • Added block setting of attributes to singular associations. The block will get called after the instance is initialized

class User < ActiveRecord::Base

has_one :account

end

 

user.build_account{ |a| a.credit_limit => 100.0 }

  • Added ActiveRecord::Base.attribute_names to return a list of attribute names. This will return an empty array if the model is abstract or the table does not exist.
  • CSV Fixtures are deprecated and support will be removed in Rails 3.2.0.
  • ActiveRecord#new, ActiveRecord#create and ActiveRecord#update_attributes all accept a second hash as an option that allows you to specify which role to consider when assigning attributes. This is built on top of Active Model’s new mass assignment capabilities:

class Post < ActiveRecord::Base

attr_accessible :title

attr_accessible :title, :published_at, :as => :admin

end

 

Post.new(params[:post], :as => :admin)

  • default_scope can now take a block, lambda, or any other object which responds to call for lazy evaluation.
  • Default scopes are now evaluated at the latest possible moment, to avoid problems where scopes would be created which would implicitly contain the default scope, which would then be impossible to get rid of via Model.unscoped.
  • PostgreSQL adapter only supports PostgreSQL version 8.2 and higher.
  • ConnectionManagement middleware is changed to clean up the connection pool after the rack body has been flushed.
  • Added an update_column method on Active Record. This new method updates a given attribute on an object, skipping validations and callbacks. It is recommended to use update_attribute unless you are sure you do not want to execute any callback, including the modification of the updated_at column. It should not be called on new records.
  • Associations with a :through option can now use any association as the through or source association, including other associations which have a :through option and has_and_belongs_to_many associations.
  • The configuration for the current database connection is now accessible via ActiveRecord::Base.connection_config.
  • limits and offsets are removed from COUNT queries unless both are supplied.

People.limit(1).count # => ‘SELECT COUNT(*) FROM people’

People.offset(1).count # => ‘SELECT COUNT(*) FROM people’

People.limit(1).offset(1).count # => ‘SELECT COUNT(*) FROM people LIMIT 1 OFFSET 1′

  • ActiveRecord::Associations::AssociationProxy has been split. There is now an Association class (and subclasses) which are responsible for operating on associations, and then a separate, thin wrapper called CollectionProxy, which proxies collection associations. This prevents namespace pollution, separates concerns, and will allow further refactorings.
  • Singular associations (has_one, belongs_to) no longer have a proxy and simply returns the associated record or nil. This means that you should not use undocumented methods such as bob.mother.create – use bob.create_mother instead.
  • Support the :dependent option on has_many :through associations. For historical and practical reasons, :delete_all is the default deletion strategy employed by association.delete(*records), despite the fact that the default strategy is :nullify for regular has_many. Also, this only works at all if the source reflection is a belongs_to. For other situations, you should directly modify the through association.
  • The behavior of association.destroy for has_and_belongs_to_many and has_many :through is changed. From now on, ‘destroy’ or ‘delete’ on an association will be taken to mean ‘get rid of the link’, not (necessarily) ‘get rid of the associated records’.
  • Previously, has_and_belongs_to_many.destroy(*records) would destroy the records themselves. It would not delete any records in the join table. Now, it deletes the records in the join table.
  • Previously, has_many_through.destroy(*records) would destroy the records themselves, and the records in the join table. [Note: This has not always been the case; previous version of Rails only deleted the records themselves.] Now, it destroys only the records in the join table.
  • Note that this change is backwards-incompatible to an extent, but there is unfortunately no way to ‘deprecate’ it before changing it. The change is being made in order to have consistency as to the meaning of ‘destroy’ or ‘delete’ across the different types of associations. If you wish to destroy the records themselves, you can do records.association.each(&:destroy).
  • Add :bulk => true option to change_table to make all the schema changes defined in a block using a single ALTER statement.

change_table(:users, :bulk => true) do |t|

t.string :company_name

t.change :birthdate, :datetime

end

  • Removed support for accessing attributes on a has_and_belongs_to_many join table. has_many :through needs to be used.
  • Added a create_association! method for has_one and belongs_to associations.
  • Migrations are now reversible可逆, meaning that Rails will figure out how to reverse your migrations. To use reversible migrations, just define the change method.

class MyMigration < ActiveRecord::Migration

def change

create_table(:horses) do

t.column :content, :text

t.column :remind_at, :datetime

end

end

end

  • Some things cannot be automatically reversed for you. If you know how to reverse those things, you should define up and down in your migration. If you define something in change that cannot be reversed, an IrreversibleMigration exception will be raised when going down.
  • Migrations now use instance methods rather than class methods:

class FooMigration < ActiveRecord::Migration

def up # Not self.up

end

end

  • Migration files generated from model and constructive migration generators (for example, add_name_to_users) use the reversible migrations change method instead of the ordinary up and down methods.
  • Removed support for interpolating插值string SQL conditions on associations. Instead, a proc should be used.

has_many :things, :conditions => ‘foo = #{bar}’ # before

has_many :things, :conditions => proc { “foo = #{bar}” } # after

 

Inside the proc, self is the object which is the owner of the association, unless you are eager loading the association, in which case self is the class which the association is within.

You can have any “normal” conditions inside the proc, so the following will work too:

has_many :things, :conditions => proc { ["foo = ?", bar] }

 

  • Previously :insert_sql and :delete_sql on has_and_belongs_to_many association allowed you to call ‘record’ to get the record being inserted or deleted. This is now passed as an argument to the proc.
  • Added ActiveRecord::Base#has_secure_password (via ActiveModel::SecurePassword) to encapsulate dead-simple password usage with BCrypt encryption and salting.

# Schema: User(name:string, password_digest:string, password_salt:string)

class User < ActiveRecord::Base

has_secure_password

end

 

  • When a model is generated add_index is added by default for belongs_to or references columns.
  • Setting the id of a belongs_to object will update the reference to the object.
  • ActiveRecord::Base#dup and ActiveRecord::Base#clone semantics语义have changed to closer match normal Ruby dup and clone semantics.
  • Calling ActiveRecord::Base#clone will result in a shallow copy of the record, including copying the frozen state. No callbacks will be called.
  • Calling ActiveRecord::Base#dup will duplicate the record, including calling after initialize hooks. Frozen state will not be copied, and all associations will be cleared. A duped record will return true for new_record?, have a nil id field, and is saveable.
  • The query cache now works with prepared statements. No changes in the applications are required.

7 Active Model

  • attr_accessible accepts an option :as to specify a role.
  • InclusionValidator, ExclusionValidator, and FormatValidator now accepts an option which can be a proc, a lambda, or anything that respond to call. This option will be called with the current record as an argument and returns an object which respond to include? for InclusionValidator and ExclusionValidator, and returns a regular expression object for FormatValidator.
  • Added ActiveModel::SecurePassword to encapsulate dead-simple password usage with BCrypt encryption and salting.
  • ActiveModel::AttributeMethods allows attributes to be defined on demand.
  • Added support for selectively enabling and disabling observers.
  • Alternate I18n namespace lookup is no longer supported.

8 Active Resource

  • The default format has been changed to JSON for all requests. If you want to continue to use XML you will need to set self.format = :xml in the class. For example,

class User < ActiveResource::Base

self.format = :xml

end

9 Active Support

  • ActiveSupport::Dependencies now raises NameError if it finds an existing constant in load_missing_constant.
  • Added a new reporting method Kernel#quietly which silences both STDOUT and STDERR.
  • Added String#inquiry as a convenience method for turning a String into a StringInquirer object.
  • Added Object#in? to test if an object is included in another object.
  • LocalCache strategy is now a real middleware class and no longer an anonymous class.
  • ActiveSupport::Dependencies::ClassCache class has been introduced for holding references to reloadable classes.
  • ActiveSupport::Dependencies::Reference has been refactored to take direct advantage of the new ClassCache.
  • Backports Range#cover? as an alias for Range#include? in Ruby 1.8.
  • Added weeks_ago and prev_week to Date/DateTime/Time.
  • Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants!.

Deprecations:

  • ActiveSupport::SecureRandom is deprecated in favor of SecureRandom from the Ruby standard library.

10 Credits

See the fulllistofcontributorstoRails for the many people who spent many hours making Rails, the stable and robust framework it is. Kudos to all of them.

Rails 3.1 Release Notes were compiled by VijayDev.

标签: gem git guide jquery learning rails release ruby

Posted in Uncategorized

版本号(the version number in baike)

版本号(version number)是版本的标识号。每一个操作系统(或广义的讲,每一个软件)都有一个版本号。版本号能使用户了解所使用的操作系统是否为最新的版本以及它所提供的功能与设施。 每一个版本号可以分为主版本号与次版本号两部分。

版本号的命名格式  例如:DOS4.0,主版本号是4,次版本号是0。

 

  版本控制比较普遍的 3 种命名格式 :

一、 GNU 风格的版本号命名格式

  主版本号 . 子版本号 [. 修正版本号 [. 编译版本号 ]]

 

  英文对照 : Major_Version_Number.Minor_Version_Number[.Revision_Number[.Build_Number]]

 

  示例 : 1.2.1, 2.0, 5.0.0 build-13124

二、 Windows 风格的版本号命名格式

  主版本号 . 子版本号 [ 修正版本号 [. 编译版本号 ]]

 

  英文对照 : Major_Version_Number.Minor_Version_Number[Revision_Number[.Build_Number]]

 

  示例: 1.21, 2.0

三、.Net Framework 风格的版本号命名格式

  主版本号.子版本号[.编译版本号[.修正版本号]]

 

  英文对照: Major_Version_Number.Minor_Version_Number[.Build_Number[.Revision_Number]]

 

  版本号由二至四个部分组成:主版本号、次版本号、内部版本号和修订号。主版本号和次版本号是必选的;内部版本号和修订号是可选的,但是如果定义了修订号部分,则内部版本号就是必选的。所有定义的部分都必须是大于或等于 0 的整数。

 

  应根据下面的约定使用这些部分:

 

  Major :具有相同名称但不同主版本号的程序集不可互换。例如,这适用于对产品的大量重写,这些重写使得无法实现向后兼容性。

 

  Minor :如果两个程序集的名称和主版本号相同,而次版本号不同,这指示显著增强,但照顾到了向后兼容性。例如,这适用于产品的修正版或完全向后兼容的新版本。

 

  Build :内部版本号的不同表示对相同源所作的重新编译。这适合于更改处理器、平台或编译器的情况。

 

  Revision :名称、主版本号和次版本号都相同但修订号不同的程序集应是完全可互换的。这适用于修复以前发布的程序集中的安全漏洞。

 

  程序集的只有内部版本号或修订号不同的后续版本被认为是先前版本的修补程序 (Hotfix) 更新。

 

版本号管理策略

一、 GNU 风格的版本号管理策略

  1.项目初版本时 , 版本号可以为 0.1 或 0.1.0, 也可以为 1.0 或 1.0.0, 如果你为人很低调 , 我想你会选择那个主版本号为 0 的方式 ;

 

  2.当项目在进行了局部修改或 bug 修正时 , 主版本号和子版本号都不变 , 修正版本号加 1;

 

  3. 当项目在原有的基础上增加了部分功能时 , 主版本号不变 , 子版本号加 1, 修正版本号复位为 0, 因而可以被忽略掉 ;

 

  4.当项目在进行了重大修改或局部修正累积较多 , 而导致项目整体发生全局变化时 , 主版本号加 1;

 

  5.另外 , 编译版本号一般是编译器在编译过程中自动生成的 , 我们只定义其格式 , 并不进行人为控制 .

二、 Window 下的版本号管理策略

  1.目初版时 , 版本号为 1.0 或 1.00;

 

  2. 当项目在进行了局部修改或 bug 修正时,主版本号和子版本号都不变 , 修正版本号加 1;

 

  3. 当项目在原有的基础上增加了部分功能时 , 主版本号不变 , 子版本号加 1, 修正版本号复位为 0, 因而可以被忽略掉 ;

 

  4. 当项目在进行了重大修改或局部修正累积较多 , 而导致项目整体发生全局变化时 , 主版本号加 1;

 

  5. 另外 , 编译版本号一般是编译器在编译过程中自动生成的 , 我们只定义其格式 , 并不进行人为控制 .

 

  另外 , 还可以在版本号后面加入 Alpha, Beta, Gamma, Current, RC (Release Candidate), Release, Stable 等后缀 , 在这些后缀后面还可以加入 1 位数字的版本号 .

 

  对于用户来说 , 如果某个软件的主版本号进行了升级 , 用户还想继续那个软件 , 则发行软件的公司一般要对用户收取升级费用 ; 而如果子版本号或修正版本号发生了升级 , 一般来说是免费的 .

 

常见版本号

  Alpha — 内部测试版 Beta — 外部测试版

 

  Cardware — 属共享软件的一种,只要给作者回复一封电邮或明信片即可。(有的作者并由此提供注册码等),目前这种形式已不多见。

 

  CHT — 繁体中文版

 

  CN/SPC — 简体中文版

 

  Corporation & Enterprise — 企业版

 

  Deluxe — 豪华版

 

  Demo — 演示版

 

  Dev — 开发专用版,程序员版本。

 

  EN — 英文版

 

  Enhance — 增强版或者加强版 属于正式版

 

  Express&Special — 特别版

 

  Final — 最终版

 

  Free — 免费版

 

  Full version — 完全版 属于正式版

 

  Green — 绿色版,破解版

 

  Mini — 迷你版(也叫精简版),只有最基本的功能

 

  Multi-language — 多语言版

 

  Plus — 属增强版,不过这种大部分是在程序界面及多媒体功能上增强。

 

  Premium — 增强版

 

  Preview — 预览版

 

  Professional — 专业版

 

  Regged/Registered — 已注册版

 

  Release — 发行版 有时间限制

 

  Retail/RTM — 零售版

 

  Shareware — 共享版

 

  Stable — 稳定版

 

  Standard — 标准版

 

  Ultimate — 旗舰版,最终版本

 

  Upgrade — 升级版

 

分类

非正式版

  α版

 

  此版本表示该软件仅仅是一个初步完成品,通常只在软件开发者内部交流,也有很少一部分发布给专业测试人员。一般而言,该版本软件的 bug 较多,普通用户最好不要安装。

 

  β(Beta)版

 

  该版本相对于α版已有了很大的改进,消除了严重的错误,但还是存在着一些缺陷,需要经过大规模的发布测试来进一步消除。这一版本通常由软件公司免费发布,用户可从相关的站点下载。通过一些专业爱好者的测试,将结果反馈给开发者,开发者们再进行有针对性的修改。该版本也不适合一般用户安装。

 

  γ版

 

  该版本已经相当成熟了,与即将发行的正式版相差无几,如果用户实在等不及了,尽可以装上一试。

 

  Trial(试用版)

 

  试用版软件在最近的几年里颇为流行,主要是得益于互联网的迅速发展。该版本软件通常都有时间限制,过期之后用户如果希望继续使用,一般得交纳一定的费用进行注册或购买。有些试用版软件还在功能上做了一定的限制。

 

  Unregistered(未注册版)

 

  未注册版与试用版极其类似,只是未注册版通常没有时间限制,在功能上相对于正式版做了一定的限制,例如绝大多数网络电话软件的注册版和未注册版,两者之间在通话质量上有很大差距。还有些虽然在使用上与正式版毫无二致,但是动不动就会弹出一个恼人的消息框来提醒你注册,如看图软件 acdsee 、智能陈桥汉字输入软件等。

 

  Demo版

 

  也称为演示版,在非正式版软件中,该版本的知名度最大。 demo 版仅仅集成了正式版中的几个功能,颇有点像 unregistered 。不同的是, demo 版一般不能通过升级或注册的方法变为正式版。

 

  以上是软件正式版本推出之前的几个版本,α、β、γ可以称为测试版,大凡成熟软件总会有多个测试版,如 windows 98 的β版,前前后后将近有 10 个。这么多的测试版一方面为了最终产品尽可能地满足用户的需要,另一方面也尽量减少了软件中的 bug 。而 trial 、 unregistered 、 demo 有时统称为演示版,这一类版本的广告色彩较浓,颇有点先尝后买的味道,对于普通用户而言自然是可以免费尝鲜了。

正式版

  不同类型的软件的正式版本通常也有区别。

 

  Release

 

  该版本意味“最终释放版”,在出了一系列的测试版之后,终归会有一个正式版本,对于用户而言,购买该版本的软件绝对不会错。该版本有时也称为标准版。一般情况下, release 不会以单词形式出现在软件封面上,取而代之的是符号 (r) ,如 windows nt(r) 4.0 、 ms-dos(r) 6.22 等。

 

  Registered

 

  很显然,该版本是与 unregistered 相对的注册版。注册版、 release 和下面所讲的 standard 版一样,都是软件的正式版本,只是注册版软件的前身有很大一部分是从网上下载的。

 

  Standard

 

  这是最常见的标准版,不论是什么软件,标准版一定存在。标准版中包含了该软件的基本组件及一些常用功能,可以满足一般用户的需求。其价格相对高一级版本而言还是“平易近人”的。

 

  Deluxe

 

  顾名思义即为“豪华版”。豪华版通常是相对于标准版而言的,主要区别是多了几项功能,价格当然会高出一大块,不推荐一般用户购买。此版本通常是为那些追求“完美”的专业用户所准备的。

 

  Reference

 

  该版本型号常见于百科全书中,比较有名的是微软的 encarta 系列。 reference 是最高级别,其包含的主题、图像、影片剪辑等相对于 standard 和 deluxe 版均有大幅增加,容量由一张光盘猛增至三张光盘,并且加入了很强的交互功能,当然价格也不菲。可以这么说,这一版本的百科全书才能算是真正的百科全书,也是发烧友们收藏的首选。

 

  Professional(专业版)

 

  专业版是针对某些特定的开发工具软件而言的。专业版中有许多内容是标准版中所没有的,这些内容对于一个专业的软件开发人员来说是极为重要的。如微软的 visual foxpro 标准版并不具备编译成可执行文件的功能,这对于一个完整的开发项目而言显然是无法忍受的,若客户机上没有 foxpro 将不能使用。如果用专业版就没有这个问题了。

 

  Enterprise(企业版)

 

  企业版是开发类软件中的极品(相当于百科全书中的 reference 版)。拥有一套这种版本的软件可以毫无障碍地开发任何级别的应用软件。如著名的 visual c++ 的企业版相对于专业版来说增加了几个附加的特性,如 sql 调试、扩展的存储过程向导、支持 as/400 对 ole db 的访问等。而这一版本的价格也是普通用户无法接受的。如微软的 visual studios 6.0 enterprise 中文版的价格为 23000 元。

专有版本

  除了以上介绍的一些版本外,还有一些专有版本名称。

 

  Update(升级版)

 

  升级版的软件是不能独立使用的,该版本的软件在安装过程中会搜索原有的正式版,如果不存在,则拒绝执行下一步。如 microsoft office 2000 升级版、 windows 9x 升级版等等。

 

  OEM版

 

  OEM 版通常是捆绑在硬件中而不单独销售的版本。将自己的产品交给别的公司去卖,保留自己的著作权,双方互惠互利,一举两得。

 

  单机(网络)版

 

  网络版在功能、结构上远比单机版复杂,如果留心一下软件的报价,你就会发现某些软件单机版和网络版的价格相差非常大,有些网络版甚至多一个客户端口就要加不少钱。

 

  普及版

 

  该版本有时也会被称为共享版,其特点是价格便宜(有些甚至完全免费)、功能单一、针对性强(当然也有占领市场、打击盗版等因素)。与试用版不同的是,该版本的软件一般不会有时间上的限制。当然,如果用户想升级,最好还是去购买正式版。

其他版本

  破解版又称绿色版,严格来说这不属于一种授权版本,因为它是针对商业版、试用版、共享版这类有使用限制的软件进行二次开发之后形成的特殊版本,也就是说,使用者可以在没有任何经济付出的条件下无限制的使用该软件的全部功能。一般通过改写原软件、制作算号器、拦截注册信息等等方式实现。

 

  以上是一些常见软件版本的简要介绍,随着软件市场行为的变化,现在也出现了一些新的版本命名方式,比如windows xp中的xp是取自于experience中的第二、第三个字母。希望以上内容能够对大家的购买、使用和下载软件有所帮助。

 

  基于商业上考虑,很多的软件都不是非常严谨的遵循这个规则的。最有名的就是微软了。例如他的 NT 系列版本。大家比较熟悉的是从 NT 4.0 开始的。 99 年推出了 windows 2000 , 2001 年推出了 windows xp , 2003 年推出了 windows 2003 ,乍一看版本区别蛮大的,但是看他们的内部版本号就会发现,变化其实并不大,只是界面变化的大了而已。这是软件公司经常干的事情。 Windows 2000 的版本号是 NT 5.0 , windows xp 的版本号是 NT 5.1 , windows 2003 的版本号是 NT 5.2 ,Windows Vista和现在的Windows7 的版本号是 NT 6.0和NT 6.1,才是跨越化的版本。这样做的话就可以持续的赚广大客户的钱。毕竟人的眼睛看得东西是最直观的,所以给人感觉也是变化最大的 。

Posted in Uncategorized

Rails Routing from the Outside In Rails

Rails Routing from the Outside In Rails来自外部的Routing

This guide covers the user-facing features of Rails routing. By referring to this guide, you will be able to:

这个guide涵盖了面向用户的Rails路由特性。通过参考这个guide,你将能够:

Understand the code in routes.rb

明白在routes.rb中的代码

  • Construct your own routes, using either the preferred resourceful style or the match method

构建属于你的routes,要么首选使用resourceful style要么使用match方法

  • Identify what parameters to expect an action to receive

确定什么样的参数expect(预期)一个action来接收(url

  • Automatically create paths and URLs using route helpers

自动的创建路径和URLs使用route helpers

  • Use advanced techniques such as constraints and Rack endpoints

使用高级的技术比如公约和Rack endpoints

1 The Purpose of the Rails Router

The Rails router recognizes URLs and dispatches them to a controller’s action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views.

Rails router组织URLsdispatches(调度)到一个controlleraction中。它也可以创建pathsURLs,避免需要hardcode string到你的视图中。

1.1 Connecting URLs to Code连接URLsCode

When your Rails application receives an incoming request

当你的Rails应用程序收到一个传入请求(incoming requests (传入请求)正传递给用户的网站内容。)

GET /patients/17

it asks the router to match it to a controller action. If the first matching route is

它请求router匹配URLs到一个controller action。如果第一个匹配的route

match “/patients/:id” => “patients#show”

the request is dispatched to the patients controller’s show action with { :id =>17} in params.

这个请求被调度给patients controllershow action以及{ :id =>17}params字典中。

1.2 Generating Paths and URLs from CodeCode创建PathsURLs

You can also generate paths and URLs. If your application contains this code:

你可以创建pathsURLs。如果你的应用程序中包含这样的代码:

@patient = Patient.find(17)

<%= link_to “Patient Record”, patient_path(@patient) %>

The router will generate the path /patients/17. This reduces the brittleness of your view and makes your code easier to understand. Note that the id does not need to be specified in the route helper.

Router将会创建path /patients/17。这样减少了你的视图的脆性并且使得你的代码更加容易明白。

2 Resource Routing: the Rails Default

Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. Instead of declaring separate routes for your index, show, new, edit, create, update and destroy actions, a resourceful route declares them in a single line of code.

Resource routing让你快速的为一个提供的resourcefulcontroller声明所有的常用routes。替代你去声明单个的index, show, new, edit, create, update and destroy actionsroutes,一个resourceful route声明它们在一个单行代码中。

When your Rails application receives an incoming request for

当你的Rails应用程序收到一个这样的传入请求

DELETE /photos/17

it asks the router to map it to a controller action. If the first matching route is

它请求router匹配URLs到一个controller action。如果第一个匹配的route

resources :photos

Rails would dispatch that request to the destroy method on the photos controller with { :id =>17} in params.

Rails将会把这个请求调度给photos controllerdestroy action以及{ :id =>17}params字典中

2.2 CRUD, Verbs, and Actions

CRUD是指在做计算处理时的增加(Create)、查询(Retrieve)(重新得到数据)、更新(Update)和删除(Delete)几个单词的首字母简写。主要被用在描述软件系统中数据库或者持久层的基本操作功能。

HTTP Verb HTTP动作

In Rails, a resourceful route provides a mapping between HTTP verbs and URLs to controller actions. By convention, each action also maps to particular CRUD operations in a database. A single entry in the routing file, such as

Rails中,一个resourceful route提供一个在HTTP verbsURLs之间的映射到controller actions。根据公约,每个action都应该映射到数据库的CRUD操作的一部分。一个单独的条目在routing文件中,像这样

resources :photos

creates seven different routes in your application, all mapping to the Photos controller:

创建七个不同的routes在你的应用程序中,所有的这些routes映射到Photos controller

 

HTTP Verb Path action used for
GET /photos index display a list of all photos
GET /photos/new new return an HTML form for creating a new photo
POST /photos create create a new photo
GET /photos/:id show display a specific photo
GET /photos/:id/edit edit return an HTML form for editing a photo
PUT /photos/:id update update a specific photo
DELETE /photos/:id destroy delete a specific photo

Rails routes are matched in the order they are specified, so if you have a resources :photos above a get 'photos/poll' the show action’s route for the resources line will be matched before the get line. To fix this, move the get line above the resources line so that it is matched first.

Rails routes在它们指定的顺序中匹配,因此如果你有一个resources :photosget 'photos/poll'的上面,resources lineshow actionroute将会在get line之前先被匹配。要修复这些,移动get lineresources line上面以确保get line被首先匹配。

2.3 Paths and URLs

Creating a resourceful route will also expose a number of helpers to the controllers in your application. In the case of resources :photos:

在你的应用程序中创建一个resourcefulroute也将会摆出一系列的controllershelpers,在这里的情况中resources :photos如下:

  • photos_path returns /photos
  • new_photo_path returns /photos/new
  • edit_photo_path(:id) returns /photos/:id/edit (for instance, edit_photo_path(10) returns /photos/10/edit)
  • photo_path(:id) returns /photos/:id (for instance, photo_path(10) returns /photos/10)

Each of these helpers has a corresponding _url helper (such as photos_url) which returns the same path prefixed with the current host, port and path prefix.

这里的每个helpers都有一个相应的_url helper(例如photos_urledit_photo_url(1)

其将会返回相同的路径后缀以及当前主机,端口和路径后缀。

####the code in my demo#####

#@tmp=post_url(1)

#@tmp=posts_url

#@tmp=edit_post_url(:id)

@tmp=new_post_url

Because the router uses the HTTP verb and URL to match inbound requests, four URLs map to seven different actions.

因为router使用HTTP verbURL来匹配入站请求,四种URLs映射到七种不同的actions中。

2.4 Defining Multiple Resources at the Same Time在同一时间定义多个Resource

If you need to create routes for more than one resource, you can save a bit of typing by defining them all with a single call to resources:

如果你需要为超过一个resource创建routes,你可以保存它们到一组中通过调用单个resources来定义所有的resource

resources :photos, :books, :videos

This works exactly the same as

这里工作类似于:

resources :photos

resources :books

resources :videos

2.5 Singular Resources 单数Resources

Sometimes, you have a resource that clients always look up without referencing an ID. For example, you would like /profile to always show the profile of the currently logged in user. In this case, you can use a singular resource to map /profile (rather than /profile/:id) to the show action.

有时候,你有一个resourceclients通常查找它们并不引用一个ID。例如,你将会希望/profile来总是显示当前的登录的用户的profile。在这种情况中,你可以使用一个单数的resource来映射/profile (rather than /profile/:id)show ation

match “profile” => “users#show”

This resourceful route这里是resourceful route

resource :geocoder

creates six different routes in your application, all mapping to the Geocoders controller:

在你的应用程序中创建六种不同的routes,所有的routes映射到Geocoderscotroller

 

HTTP Verb Path action used for
GET /geocoder/new new return an HTML form for creating the geocoder
POST /geocoder create create the new geocoder
GET /geocoder show display the one and only geocoder resource
GET /geocoder/edit edit return an HTML form for editing the geocoder
PUT /geocoder update update the one and only geocoder resource
DELETE /geocoder destroy delete the geocoder resource

Because you might want to use the same controller for a singular route (/account) and a plural route (/accounts/45), singular resources map to plural controllers.

因为你可能希望对单数route(/account)和复数route(/accounts/45)使用相同的controller,单数resources映射到复数controllers

A singular resourceful route generates these helpers:

一个单数resourceful route创建这些helpers

  • new_geocoder_path returns /geocoder/new
  • edit_geocoder_path returns /geocoder/edit
  • geocoder_path returns /geocoder

As with plural resources, the same helpers ending in _url will also include the host, port and path prefix.

就像plural resources,相同的以_url结尾的helpers同样包含,hostport和路径后缀。

2.6 Controller Namespaces and Routing

You may wish to organize groups of controllers under a namespace. Most commonly, you might group a number of administrative controllers under an Admin:: namespace. You would place these controllers under the app/controllers/admin directory, and you can group them together in your router:

你可能希望通过namespace分组组织controllers。通常大多数情况,你可以分组一系列的administrative controllers到一个Admin::名称空间下面。你将会放置这些controllersapp/controllers/admin目录中,并且你可以在你的router中分组他们在一起

namespace :admin do

resources :posts, :comments

end

This will create a number of routes for each of the posts and comments controller. For Admin::PostsController, Rails will create:

这将会对于每一个postscomments controller创建若干的routes。对于Admin::PostsControllerRails将会创建:

 

HTTP Verb Path action named helper
GET /admin/posts index admin_posts_path
GET /admin/posts/new new new_admin_post_path
POST /admin/posts create admin_posts_path
GET /admin/posts/:id show admin_post_path(:id)
GET /admin/posts/:id/edit edit edit_admin_post_path(:id)
PUT /admin/posts/:id update admin_post_path(:id)
DELETE /admin/posts/:id destroy admin_post_path(:id)

If you want to route /posts (without the prefix /admin) to Admin::PostsController, you could use

如果你想Admin::PostsControllerroute /posts(without the prefix /admin),你可以使用

#admin中取出,重新声明为独立的resources

scope :module => "admin" do

resources :posts, :comments

end

or, for a single case

resources :posts, :module => "admin"

If you want to route /admin/posts to PostsController (without the Admin:: module prefix), you could use

scope “/admin” do

resources :posts, :comments

end

or, for a single case

resources :posts, :path => "/admin/posts"

In each of these cases, the named routes remain the same as if you did not use scope. In the last case, the following paths map to PostsController:

在每个这样的情况中,named routes保持不变,如果你没有使用范围。在最后,随后的paths映射到PostsController

 

HTTP Verb Path action named helper
GET /admin/posts index posts_path
GET /admin/posts/new new new_post_path
POST /admin/posts create posts_path
GET /admin/posts/:id show post_path(:id)
GET /admin/posts/:id/edit edit edit_post_path(:id)
PUT /admin/posts/:id update post_path(:id)
DELETE /admin/posts/:id destroy post_path(:id)

2.7 Nested Resources嵌套Resource

It’s common to have resources that are logically children of other resources. For example, suppose your application includes these models:

在通常情况中有resources是其他的resources逻辑上的children。例如,假设你的应用程序包含这些models

class Magazine < ActiveRecord::Base

has_many :ads

end

 

class Ad < ActiveRecord::Base

belongs_to :magazine

end

Nested routes allow you to capture this relationship in your routing. In this case, you could include this route declaration:

嵌套routes允许你捕捉这些关系在你的routing中。在这里的情况中,你可包含这样的声明:

resources :magazines do

resources :ads

end

In addition to the routes for magazines, this declaration will also route ads to an AdsController. The ad URLs require a magazine:

除了magazinesroutes,这里也同样声明route adsAdsControlleradURLs需要一个magazine(对象):

 

HTTP Verb Path action used for
GET /magazines/:id/ads index display a list of all ads for a specific magazine
GET /magazines/:id/ads/new new return an HTML form for creating a new ad belonging to a specific magazine
POST /magazines/:id/ads create create a new ad belonging to a specific magazine
GET /magazines/:id/ads/:id show display a specific ad belonging to a specific magazine
GET /magazines/:id/ads/:id/edit edit return an HTML form for editing an ad belonging to a specific magazine
PUT /magazines/:id/ads/:id update update a specific ad belonging to a specific magazine
DELETE /magazines/:id/ads/:id destroy delete a specific ad belonging to a specific magazine

This will also create routing helpers such as magazine_ads_url and edit_magazine_ad_path. These helpers take an instance of Magazine as the first parameter (magazine_ads_url(@magazine)).

这里也将会创建routing helpers例如magazine_ads_urledit_magazine_ad_path。这些helpers获取一个Magazine的实例作为第一个参数(magazine_ads_url(@magazine))。

2.7.1 Limits to Nesting嵌套的局限

You can nest resources within other nested resources if you like. For example:

你可以嵌套resources在其他嵌套resources中如果你喜欢。例如:

resources :publishers do

resources :magazines do

resources :photos

end

end

Deeply-nested resources quickly become cumbersome. In this case, for example, the application would recognize paths such as

深层的嵌套resources相当的累赘。在这样的情况下,例如,应用程序将会这样组织路径

/publishers/1/magazines/2/photos/3

The corresponding route helper would be publisher_magazine_photo_url, requiring you to specify objects at all three levels. Indeed, this situation is confusing enough that a popular article by Jamis Buck proposes a rule of thumb for good Rails design:

相应的route helper将会是publisher_magazine_photo_url这需要你指定三个级别的所有对象。事实上,这种情况下太混乱了一篇受欢迎的文章来自Jamis Buck,关于一个设计良好的Rails的经验法则:

Resources should never be nested more than 1 level deep.

2.8 Creating Paths and URLs From Objects

In addition to using the routing helpers, Rails can also create paths and URLs from an array of parameters. For example, suppose you have this set of routes:

除了使用routing helpersRails也可以从一个parameters数组创建pathsURLs。例如,假设你有这样的组routes

resources :magazines do

resources :ads

end

When using magazine_ad_path, you can pass in instances of Magazine and Ad instead of the numeric IDs.

在使用magazine_ad_path的时候,你可以传递Magazine and Ad的实例替代数字IDs

<%= link_to “Ad details”, magazine_ad_path(@magazine, @ad) %>

You can also use url_for with a set of objects, and Rails will automatically determine which route you want:

你同样也可以使用url_for和一组对象,那么Rails将会自动的决定那个route是你希望的:

<%= link_to “Ad details”, url_for([@magazine, @ad]) %>

In this case, Rails will see that @magazine is a Magazine and @ad is an Ad and will therefore use the magazine_ad_path helper. In helpers like link_to, you can specify just the object in place of the full url_for call:

在这里,Rails将会明白@magazineMagazine并且@adAd于此将会因此使用magazine_ad_path helper。在就像link_tohelpers中,你可以指定仅仅对象在url_for调用中:

<%= link_to “Ad details”, [@magazine, @ad] %>

If you wanted to link to just a magazine, you could leave out the Array:

如果你想仅仅link到一个magazine,你可以省去数组:

<%= link_to “Magazine details”, @magazine %>

This allows you to treat instances of your models as URLs, and is a key advantage to using the resourceful style.

这让你处理models的实例为URLs,并且这也是使用resourceful style的关键优势。

2.9 Adding More RESTful Actions添加更多的RESTful Action

You are not limited to the seven routes that RESTful routing creates by default. If you like, you may add additional routes that apply to the collection or individual members of the collection.

你并不限制于RESTful routing默认创建的七个routes。如果你喜欢,你可以添加额外的routes用于多个或者个别的collection

2.9.1 Adding Member Routes

To add a member route, just add a member block into the resource block:

添加一个member route,仅仅添加一个memberblockresource block中:

resources :photos do

member do

get ‘preview’

end

end

This will recognize /photos/1/preview with GET, and route to the preview action of PhotosController. It will also create the preview_photo_url and preview_photo_path helpers.

Within the block of member routes, each route name specifies the HTTP verb that it will recognize. You can use get, put, post, or delete here. If you don’t have multiple member routes, you can also pass :on to a route, eliminating the block:

memberroutes中,每个route名字指定HTTP verb这是将会组织的。在这里你可以使用get, put, post, or delete。如果你没有多个member routes,你同样也可以传递:on到一个route,消除block

resources :photos do

get ‘preview’, :on => :member

end

2.9.2 Adding Collection Routes

To add a route to the collection:

添加一个routecollection

resources :photos do

collection do

get ‘search’

end

end

This will enable Rails to recognize paths such as /photos/search with GET, and route to the search action of PhotosController. It will also create the search_photos_url and search_photos_path route helpers.

这将使Rails能够像这样/photos/search with GET组织路径,并且routePhotosControllersearch action。它将同样创建search_photos_urlsearch_photos_path route helpers

Just as with member routes, you can pass :on to a route:

仅仅对于member routes,你可以传递:on给一个route

resources :photos do

get ‘search’, :on => :collection

end

2.9.3 A Note of Caution一个慎重的提醒

If you find yourself adding many extra actions to a resourceful route, it’s time to stop and ask yourself whether you’re disguising the presence of another resource.

如果你发现你自己添加很多额外的action到一个resourcefulroute,是时候停下来并问你自己

是否你在伪造另一个resource

3 Non-Resourceful Routes- Resourceful Routes

In addition to resource routing, Rails has powerful support for routing arbitrary URLs to actions. Here, you don’t get groups of routes automatically generated by resourceful routing. Instead, you set up each route within your application separately.

除了resource routingRails对任意的URLsactions有强力的支持。这里,你没有得到被resourceful routing自动创建的groups of routes。作为替代,在你的应用程序中分别设置每个route

While you should usually use resourceful routing, there are still many places where the simpler routing is more appropriate. There’s no need to try to shoehorn every last piece of your application into a resourceful framework if that’s not a good fit.

即使你应该通常使用resourceful routing,这里仍然有很多地方简单的routing更加适合。这里不需要尝试将你的应用程序最后写成一个resourceful framework如果这样并不合适。

In particular, simple routing makes it very easy to map legacy URLs to new Rails actions.

特别是,简单的路routing,使得它很容易映射(传入的)现有的URL映射到新的Rails action

3.1 Bound Parameters绑定参数

When you set up a regular route, you supply a series of symbols that Rails maps to parts of an incoming HTTP request. Two of these symbols are special: :controller maps to the name of a controller in your application, and :action maps to the name of an action within that controller. For example, consider one of the default Rails routes:

当你设定一个正则route,你供应一系列的字符,其将通过Rails映射到传入HTTP请求的一部分。这些字符的两部分分别是::controller映射到你应用程序中的一个controller,并且:action映射到在指定的controller中的一个action。例如思考一个默认的Rails routes

match ‘:controller(/:action(/:id))’

If an incoming request of /photos/show/1 is processed by this route (because it hasn’t matched any previous route in the file), then the result will be to invoke the show action of the PhotosController, and to make the final parameter "1" available as params[:id]. This route will also route the incoming request of /photos to PhotosController#index, since :action and :id are optional parameters, denoted by parentheses.

如果传入请求/photos/show/1 is processed by this route (因为它并没有被先前的route文件中任何的route匹配成功),接着这个结果将会调用PhotosControllershow action,并且使得最后的参数1可用于params[:id]。这个route也还会route传入请求/photosPhotosController#index,因为:action:id是被括号包起来的可选参数。

3.2 Dynamic Segments动态分割

You can set up as many dynamic segments within a regular route as you like. Anything other than :controller or :action will be available to the action as part of params. If you set up this route:

你可以设置你希望的数目的dynamic segments在一个正则route中。超过:controller or :action的其他部分(是可用的)在action作为params第一部分。如果你设定这样的route

match ':controller/:action/:id/:user_id'

An incoming path of /photos/show/1/2 will be dispatched to the show action of the PhotosController. params[:id] will be "1", and params[:user_id] will be "2".

一个传入路径/photos/show/1/2将会被调度给PhotosControllershow actionparams[:id] will be "1", and params[:user_id] will be "2".

You can’t use namespace or :module with a :controller path segment. If you need to do this then use a constraint on :controller that matches the namespace you require. e.g:

你不能对一个:controller路径segment使用namespace或者:module。如果你需要这么做那么使用对:controller一个限制使其匹配你请求的namespace。例如:

match ':controller(/:action(/:id))', :controller => /admin/[^/]+/

 

By default dynamic segments don’t accept dots – this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment add a constraint which overrides this – for example :id => /[^/]+/ allows anything except a slash.

默认的动态分割不接受dots.——这是因为dot被作为格式化routes的一个分割。如果你需要在一个dynamic segment中使用dot,添加一个限制来重写它——例如:id => /[^/]+/允许除了斜线之外的任何字符。

3.3 Static Segments

You can specify static segments when creating a route:

match ‘:controller/:action/:id/with_user/:user_id’

This route would respond to paths such as /photos/show/1/with_user/2. In this case, params would be { :controller =>photos, :action =>show, :id =>1, :user_id =>2}.

3.4 The Query String查询字符串

The params will also include any parameters from the query string. For example, with this route:

params将也会包含来自查询字符串的任何参数。例如,使用这个route

match ‘:controller/:action/:id’

An incoming path of /photos/show/1?user_id=2 will be dispatched to the show action of the Photos controller. params will be { :controller =>photos, :action =>show, :id =>1, :user_id =>2}.

一个传入路径/photos/show/1?user_id=2将会被调度给Photos controllershow actionparams将会是{ :controller =>photos, :action =>show, :id =>1, :user_id =>2}

3.5 Defining Defaults默认定义

You do not need to explicitly use the :controller and :action symbols within a route. You can supply them as defaults:

你不需要准确的使用:controller:action字符在一个route中。你可以默认的提供他们:

match ‘photos/:id’ => ‘photos#show’

With this route, Rails will match an incoming path of /photos/12 to the show action of PhotosController.

通过这个routeRails将会匹配一个传入路径/photos/12PhotosControllershow action

You can also define other defaults in a route by supplying a hash for the :defaults option. This even applies to parameters that you do not specify as dynamic segments. For example:

你同样也可以在route中定义其他的默认(设置)通过提供一个hash字典给:defaults选项。这甚至会应用于不需要指定参数作为动态分割。例如:

match ‘photos/:id’ => ‘photos#show’, :defaults => { :format => ‘jpg’ }

Rails would match photos/12 to the show action of PhotosController, and set params[:format] to "jpg".

Rails将会匹配photos/12PhotosControllershow action,并且设置params[:format] to "jpg"

3.6 Naming Routes

You can specify a name for any route using the :as option.

你可以指定一个name给任何route使用:as选项。

match ‘exit’ => ‘sessions#destroy’, :as => :logout

This will create logout_path and logout_url as named helpers in your application. Calling logout_path will return /exit

这里将会在应用程序中创建logout_pathlogout_url作为(刚才)命名的routehelpers。调用logout_path将会返回/exit

3.7 HTTP Verb Constraints 限定HTTP 动作

You can use the :via option to constrain the request to one or more HTTP methods:

你可以使用:via选项来限定请求一个或多个(HTTP)方法:

match ‘photos/show’ => ‘photos#show’, :via => :get

There is a shorthand version of this as well:

这里的短操作版本同样也是可以的:

get ‘photos/show’

You can also permit more than one verb to a single route:

你也可以运行超过一个动作到一个单独的route

match ‘photos/show’ => ‘photos#show’, :via => [:get, :post]

3.8 Segment Constraints分割限制

You can use the :constraints option to enforce a format for a dynamic segment:

你可以使用:constraints选项来强制一个动态分割的格式:

match ‘photos/:id’ => ‘photos#show’, :constraints => { :id => /[A-Z]d{5}/ }

This route would match paths such as /photos/A12345. You can more succinctly express the same route this way:

这个route将会匹配像这样的路径/photos/A12345。你可以使用这样的方式来更加简洁的表达相同的route

match ‘photos/:id’ => ‘photos#show’, :id => /[A-Z]d{5}/

:constraints takes regular expressions with the restriction that regexp anchors can’t be used. For example, the following route will not work:

:constraints获取的正则表达式,其限定了正则表达式的锚不能被使用。例如下面的route将不会工作(使用了^锚指定从这里开始):

match ‘/:id’ => ‘posts#show’, :constraints => {:id => /^d/}

However, note that you don’t need to use anchors because all routes are anchored at the start.

然而,注意你不需要使用锚因为所有的routes锚定在开始位置。

For example, the following routes would allow for posts with to_param values like 1-hello-world that always begin with a number and users with to_param values like david that never begin with a number to share the root namespace:

例如,下面的route将会允许poststo_param1-hello-world的值,其总是以一个数字和useruserto_param的值就像david)它从不以数字开始来share根名称空间。

match ‘/:id’ => ‘posts#show’, :constraints => { :id => /d.+/ }

match ‘/:username’ => ‘users#show’

3.9 Request-Based Constraints Request-Based的限制

You can also constrain a route based on any method on the Request object that returns a String.

You specify a request-based constraint the same way that you specify a segment constraint:

你也可以限制一个route 基于任何方法在Request对象时它都会返回一个String

你指定一个request-basedcontraint和你指定一个segment constaint是一样的。

match “photos”, :constraints => {:subdomain => “admin”}

You can also specify constraints in a block form:

你也可以指定限制在一个block form中:

namespace :admin do

constraints :subdomain => “admin” do

resources :photos

end

end

3.10 Advanced Constraints高级constraints

If you have a more advanced constraint, you can provide an object that responds to matches? that Rails should use. Let’s say you wanted to route all users on a blacklist to the BlacklistController. You could do:

如果你有一个更高级的contraint,你可以提供一个对象,Rails将会使用matches?回应这个对象。

让我来告诉你要想route所有的用户在一个黑名单中匹配(通过BlacklistControllermatches?方法)。你应该:

class BlacklistConstraint

def initialize

@ips = Blacklist.retrieve_ips

end

 

def matches?(request)

@ips.include?(request.remote_ip)

end

end

 

TwitterClone::Application.routes.draw do

match “*path” => “blacklist#index”,

:constraints => BlacklistConstraint.new

end

3.11 Route Globbing

Route globbing is a way to specify that a particular parameter should be matched to all the remaining parts of a route. For example

Route globbing是一种方式来指定特定的paramerter应该被一个route的其余的所有部分匹配。例如

match ‘photos/*other’ => ‘photos#unknown’

This route would match photos/12 or /photos/long/path/to/12, setting params[:other] to "12" or "long/path/to/12".

这个route将会匹配photos/12或者/photos/long/path/to/12,设置params[:other] to "12""long/path/to/12"

Wildcard segments can occur anywhere in a route. For example,

通配符分割可以发生在一个route的任何地方。例如,

match ‘books/*section/:title’ => ‘books#show’

would match books/some/section/last-words-a-memoir with params[:section] equals "some/section", and params[:title] equals "last-words-a-memoir".

将会匹配books/some/section/last-words-a-memoirparams[:section]等于"some/section",以及params[:title]相当于"last-words-a-memoir"

Technically a route can have even more than one wildcard segment. The matcher assigns segments to parameters in an intuitive way. For example,

从技术上讲一个route可以有甚至超过一个通配符的分割。matcher分配segments到参数是一个直观的方式。例如,

match ‘*a/foo/*b’ => ‘test#index’ # *a这一部分通配为a

would match zoo/woo/foo/bar/baz with params[:a] equals "zoo/woo", and params[:b] equals "bar/baz".

Starting from Rails 3.1, wildcard routes will always match the optional format segment by default. For example if you have this route:

match '*pages' => 'pages#show'

By requesting "/foo/bar.json", your params[:pages] will be equals to "foo/bar" with the request format of JSON. If you want the old 3.0.x behavior back, you could supply :format => false like this:

match '*pages' => 'pages#show', :format => false

If you want to make the format segment mandatory, so it cannot be omitted, you can supply :format => true like this:

match '*pages' => 'pages#show', :format => true

3.12 Redirection

You can redirect any path to another path using the redirect helper in your router:

你可以重定向任何path到另一个path使用redirect helper在你的router

match “/stories” => redirect(“/posts”)

You can also reuse dynamic segments from the match in the path to redirect to:

match “/stories/:name” => redirect(“/posts/%{name}”)

You can also provide a block to redirect, which receives the params and (optionally) the request object:

match “/stories/:name” => redirect {|params| “/posts/#{params[:name].pluralize}” }

match “/stories” => redirect {|p, req| “/posts/#{req.subdomain}” }

In all of these cases, if you don’t provide the leading host (http://www.example.com), Rails will take those details from the current request.

3.13 Routing to Rack Applications

Instead of a String, like "posts#index", which corresponds to the index action in the PostsController, you can specify any Rackapplication as the endpoint for a matcher.

match “/application.js” => Sprockets

As long as Sprockets responds to call and returns a [status, headers, body], the router won’t know the difference between the Rack application and an action.

For the curious, "posts#index" actually expands out to PostsController.action(:index), which returns a valid Rack application.

3.14 Using root

You can specify what Rails should route "/" to with the root method:

root :to => ‘pages#main’

You should put the root route at the top of the file, because it is the most popular route and should be matched first. You also need to delete the public/index.html file for the root route to take effect.

4 Customizing Resourceful Routes

While the default routes and helpers generated by resources :posts will usually serve you well, you may want to customize them in some way. Rails allows you to customize virtually any generic part of the resourceful helpers.

4.1 Specifying a Controller to Use

The :controller option lets you explicitly specify a controller to use for the resource. For example:

resources :photos, :controller => “images”

will recognize incoming paths beginning with /photos but route to the Images controller:

HTTP Verb Path action named helper
GET /photos index photos_path
GET /photos/new new new_photo_path
POST /photos create photos_path
GET /photos/:id show photo_path(:id)
GET /photos/:id/edit edit edit_photo_path(:id)
PUT /photos/:id update photo_path(:id)
DELETE /photos/:id destroy photo_path(:id)

Use photos_path, new_photo_path, etc. to generate paths for this resource.

4.2 Specifying Constraints

You can use the :constraints option to specify a required format on the implicit id. For example:

This declaration constraints the :id parameter to match the supplied regular expression. So, in this case, the router would no longer match /photos/1 to this route. Instead, /photos/RR27 would match.

You can specify a single constraint to apply to a number of routes by using the block form:

constraints(:id => /[A-Z][A-Z][0-9]+/) do

resources :photos

resources :accounts

end

Of course, you can use the more advanced constraints available in non-resourceful routes in this context.

 

By default the :id parameter doesn’t accept dots – this is because the dot is used as a separator for formatted routes. If you need to use a dot within an :id add a constraint which overrides this – for example :id => /[^/]+/ allows anything except a slash.

4.3 Overriding the Named Helpers

The :as option lets you override the normal naming for the named route helpers. For example:

resources :photos, :as => “images”

will recognize incoming paths beginning with /photos and route the requests to PhotosController, but use the value of the :as option to name the helpers.

HTTP verb Path action named helper
GET /photos index images_path
GET /photos/new new new_image_path
POST /photos create images_path
GET /photos/:id show image_path(:id)
GET /photos/:id/edit edit edit_image_path(:id)
PUT /photos/:id update image_path(:id)
DELETE /photos/:id destroy image_path(:id)

4.4 Overriding the new and edit Segments重写newedit Segments

The :path_names option lets you override the automatically-generated “new” and “edit” segments in paths:

resources :photos, :path_names => { :new => ‘make’, :edit => ‘change’ }

This would cause the routing to recognize paths such as

/photos/make

/photos/1/change

The actual action names aren’t changed by this option. The two paths shown would still route to the new and edit actions.

 

If you find yourself wanting to change this option uniformly for all of your routes, you can use a scope.

scope :path_names => { :new => “make” } do

# rest of your routes

end

4.5 Prefixing the Named Route Helpers

You can use the :as option to prefix the named route helpers that Rails generates for a route. Use this option to prevent name collisions between routes using a path scope

scope “admin” do

resources :photos, :as => “admin_photos”

end

 

resources :photos

This will provide route helpers such as admin_photos_path, new_admin_photo_path etc.这将会提供比如 admin_photos_path, new_admin_photo_path等这样的route helpers

To prefix a group of route helpers, use :as with scope:

scope “admin”, :as => “admin” do

resources :photos, :accounts

end

 

resources :photos, :accounts

This will generate routes such as admin_photos_path and admin_accounts_path which map to /admin/photos and /admin/accounts respectively.

The namespace scope will automatically add :as as well as :module and :path prefixes.

You can prefix routes with a named parameter also:

scope “:username” do

resources :posts

end

This will provide you with URLs such as /bob/posts/1 and will allow you to reference the username part of the path as params[:username] in controllers, helpers and views.

4.6 Restricting the Routes Created限制routes被创建

By default, Rails creates routes for the seven default actions (index, show, new, create, edit, update, and destroy) for every RESTful route in your application. You can use the :only and :except options to fine-tune this behavior. The :only option tells Rails to create only the specified routes:

默认的,Rails按照七种默认的actionindex, show, new, create, edit, update, and destroy)为你应用程序中的每个RESTful route创建routes

resources :photos, :only => [:index, :show]

Now, a GET request to /photos would succeed, but a POST request to /photos (which would ordinarily be routed to the create action) will fail.

现在一个GET请求到/photos将会成功,但是一个POST/photos(其按理将会routecreate action)将会失败。

The :except option specifies a route or list of routes that Rails should not create:

resources :photos, :except => :destroy

In this case, Rails will create all of the normal routes except the route for destroy (a DELETE request to /photos/:id).

If your application has many RESTful routes, using :only and :except to generate only the routes that you actually need can cut down on memory use and speed up the routing process.

如果你的应用程序中有很多 RESTful routes,使用:only and :except来生成仅仅你实际需要的route能够消减内存使用和提速routing 进程。

4.7 Translated Paths翻译路径

Using scope, we can alter path names generated by resources:

使用scope,我们可以别名resources生成的路径name

scope(:path_names => { :new => “neu”, :edit => “bearbeiten” }) do

resources :categories, :path => “kategorien”

end

Rails now creates routes to the CategoriesController.

HTTP verb Path action named helper
GET /kategorien index categories_path
GET /kategorien/neu new new_category_path
POST /kategorien create categories_path
GET /kategorien/:id show category_path(:id)
GET /kategorien/:id/bearbeiten edit edit_category_path(:id)
PUT /kategorien/:id update category_path(:id)
DELETE /kategorien/:id destroy category_path(:id)

4.8 Overriding the Singular Form

If you want to define the singular form of a resource, you should add additional rules to the Inflector.

如果你想定义一个单数形式的resource,你应该添加补充的rulesInflector

ActiveSupport::Inflector.inflections do |inflect|

inflect.irregular ‘tooth’, ‘teeth’

end

4.9 Using :as in Nested Resources在嵌套resources中使用:as

The :as option overrides the automatically-generated name for the resource in nested route helpers. For example,

:as选项覆盖嵌套的resource自动生成的route的名字。例如:

resources :magazines do

resources :ads, :as => ‘periodical_ads’

end

This will create routing helpers such as magazine_periodical_ads_url and edit_magazine_periodical_ad_path.

5 Inspecting and Testing Routes检查和测试routes

Rails offers facilities for inspecting and testing your routes.

Rails提供设施来检查和测试你的routes

5.1 Seeing Existing Routes with rake使用rake来查看存在的routes

If you want a complete list of all of the available routes in your application, run rake routes command. This will print all of your routes, in the same order that they appear in routes.rb. For each route, you’ll see:

如果你需要一个你应用程序中可用的完整的list,运行 rake routes命令。这将会打印所有你的routes(到终端),与routes.rb中出现的顺序一样。对于每个route,你将会看到:

  • The route name (if any)
  • The HTTP verb used (if the route doesn’t respond to all verbs)
  • The URL pattern to match 匹配的URL模式
  • The routing parameters for the route

For example, here’s a small section of the rake routes output for a RESTful route:

          users GET  /users          {:controller=>"users", :action=>"index"}
formatted_users GET  /users.:format  {:controller=>"users", :action=>"index"}
                POST /users          {:controller=>"users", :action=>"create"}
                POST /users.:format  {:controller=>"users", :action=>"create"}

You may restrict the listing to the routes that map to a particular controller setting the CONTROLLER environment variable:

你可以限制列出的routes映射到一个别的controller设置 CONTROLLER环境变量:

$ CONTROLLER=users rake routes

You’ll find that the output from rake routes is much more readable if you widen your terminal window until the output lines don’t wrap.

你会发现如果你扩大到你的终端不自动换行,来自rake routes会更具可读性。

5.2 Testing Routes

Routes should be included in your testing strategy策略 (just like the rest of your application). Rails offers three built-in assertions designed to make testing routes simpler:

  • assert_generates
  • assert_recognizes
  • assert_routing
5.2.1 The assert_generates Assertion

assert_generates asserts that a particular set of options generate a particular path and can be used with default routes or custom routes.

assert_generates断言是一个特别的设置选项生成一个特别的路径并且可以与默认的routes和定制的routes

assert_generates “/photos/1″, { :controller => “photos”, :action => “show”, :id => “1” }

assert_generates “/about”, :controller => “pages”, :action => “about”

5.2.2 The assert_recognizes Assertion

assert_recognizes is the inverse of assert_generates. It asserts that a given path is recognized and routes it to a particular spot in your application.

assert_recognizesassert_generates的逆。它断言一个给定的path是被承认的并route到应用程序中的特定地点。

assert_recognizes({ :controller => "photos", :action => "show", :id => "1" }, "/photos/1")

You can supply a :method argument to specify the HTTP verb:

你可以提供一个:method参数来指定HTTP verbe

assert_recognizes({ :controller => “photos”, :action => “create” }, { :path => “photos”, :method => :post })

assert_recognizes({ :controller => “photos”, :action => “create” }, { :path => “photos”, :method => :post })

5.2.3 The assert_routing Assertion

The assertion checks the route both ways: it tests that the path generates the options, and that the options generate the path. Thus, it combines the functions of assert_generates and assert_recognizes.

断言 assert_routing检测route两方面:它测试访问路径生成选项,并且测试这个选项生成的路径。这样,它联合了 assert_generates and assert_recognizes的功能。

assert_routing({ :path => “photos”, :method => :post }, { :controller => “photos”, :action => “create” })

标签: guide http rails route ruby translate

Posted in Uncategorized

理解JSON:3分钟课程

如果你跟我一样(我担心你就是),那么,到目前为止,这应该是你对JSON的经验:

  1. 两个月前你从没听说过JSON
  2. 一个月前你听说了这个词但没有留意
  3. 一周前你发现这个词被提到多次,开始想,没错 … 又有一些垃圾东西要学了
  4. 今天你被心灵深处的一个闹铃闹醒,心想:这该死的json究竟是个什么东西?为什么突然间到处都是它了!

于是晚上我乘坐了一辆慢腾腾的公交回到家(周五通常都是很慢),然后给自己找了一大堆关于JSON资料。所以我可以文雅的带你进入JSON的大门。

这就开始了 …

这几个字母是什么意思?

JavaScript Object Notation.

[一个滑稽的名字。它应该被称作Lightweight Ecmascript Object Notation, 或简称 'LEON'。 ;-) ]

它是个什么东西?

JSON是一种传递对象的语法,对象可以是name/value对,数组和其他对象。

下面是一小段JSON代码:

点击收起{"skillz": {
	"web":[
		{"name": "html",
		 "years": "5"
		},
		{"name": "css",
		 "years": "3"
		}],
	"database":[
		{"name": "sql",
		 "years": "7"
		}]
}}

你看懂了吧?那么当你再看到它时就知道它是JSON了。主要部分:

花括弧,方括弧,冒号和逗号

  1. 花括弧表示一个“容器”
  2. 方括号装载数组
  3. 名称和值用冒号隔开
  4. 数组元素通过逗号隔开

把它想成“得了厌食症的XML”

(如果你跟我一样老,可以把它想成有层次关系的’.INI’文件)

(如果你是个自以为是的Lisp小丑,可以把它想成”S-expressions”,自以为是吧)

JSON很像XML,因为:

  1. 他们都“自我描述”,这意味着值都是可列举的,是“人类可读”的
  2. 都是有层级的。(例如你可以在值里再存放值)
  3. 都能被多种的编程语言解析和使用
  4. 都能使用AJAX方法来传递(例如httpWebRequest)

JSON跟XML不一样,因为:

  1. XML里在元素的开始和结尾处有尖括号和标签名:JSON使用花括号,而且只在数据的开始和结束时使用。
  2. JSON更简练,毫无疑问更适合人类书写,也许也能让我们更快速的阅读。
  3. JSON可以在JavaScript里简单的传递到eval()方法里使用
  4. JSON里有数组{每个元素没有自己的名称}
  5. 在XML里你可以对一个元素使用任意想要的名称,在JSON里你不能使用Javascript里的保留字

可是为什么?它有什么好的?

当你写ajax之类的东西时,如果你使用JSON,你就勉去了手工拼写XML。更迅速。

同样,当你写ajax之类的东西时,怎样最简单?XML方式还是JSON方式:

XML方式:

  1. 取回一个XML文件
  2. 循环它,从中提取值
  3. 处理这些值,等

对比

JSON方式:

  1. 取回JSON字符串。
  2. ‘eval’ JSON数据

它是面向对象的吗?

No,严格的说,不是。

就像是VB6里的面向对象一样。它提供了很好的封装机制,你可以使用它把数据和方法分离出来,但它不提供任何的继承,多型,接口,或其它类似的面向对象的东西

很显然,它是使javascript变得更易于维护,分析和复用的方向上前进了一步。

Thomas Frank写了一个灵巧的javascript库,叫做classyJSON,它在JSON代码上增加了继承和定义范围等特征。

它只是用在客户端吗?

是,也不是。在服务器端你可以容易的把对象序列化成JSON或反之。对于.net,程序员可以使用类似Json.net的类库使这些操作自动化(我估计是使用反射机制),或你使用自己的程序来做这些事,可能会更快些。

3分钟将近结束….

就我所知,JSON是由一个叫做Douglas Crockford的家伙发明的。如果你喜欢的话,可以看一下他的网站,他非常的有趣。

这就是全部。

我在几分钟的时间里只能整理出这些东西——所有我说的有些东西可能完全是错的。如果是这样,请留言告诉我,告诉我我有多傻。我会很高兴的纠正任何一个错误。祝你好运!

(边注:如果你把 { 和 } 替换成”<” 和 “/>”,把”:” 换成 “/”… 你会得到一个非常像gaXml的东西。有趣的世界。

(边注2:Jason 和 Ajax 都是希腊神话中的英雄。预告:另外一些即将出现的技术垃圾包括:Heracles, Perseus, Deucalion, Theseus
and Bellerophon。)

Posted in Uncategorized

16 条技巧让你更高效使用 SSH

SSH有很多非常酷的特性,如何它是你每天的工作伴侣,那么我想你有必要了解以下16条高效使用SSH的秘籍,它们帮你节省的时间肯定会远远大于你用来配置它们的时间。

1. 多条连接共享

如果你需要在多个窗口中打开到同一个服务器的连接,而不想每次都输入用户名,密码,或是等待连接建立,那么你可以配置SSH的连接共享选项,在本地打开你的SSH配置文件,通常它们位于~/.ssh/config,然后添加下面2行:

ControlMaster auto
ControlPath /tmp/ssh_mux_%h_%p_%r

现在试试断开你与服务器的连接,并建立一条新连接,然后打开一个新窗口,再创建一条连接,你会发现,第二条连接几乎是在瞬间就建立好了。

Windows用户

如果你是Windows用户,很不幸,最流行的开源SSH客户端Putty并不支持这个特性,但是Windows上也有OpenSSH的实现,比如这个Copssh,如果你觉得下面的一些技巧对你很有帮助,或许你应该试试Copssh。

文件传输

连接共享不止可以帮助你共享多个SSH连接,如果你需要通过SFTP与服务器传输文件,你会发现,它们使用的依然是同一条连接,如果你使用的 Bash,你会发现,你甚至SSH甚至支持Tab对服务器端文件进行自动补全,共享连接选项对于那些需要借助SSH的工具,比如rsync,git等等也 同样有效。

2. 长连接

如果你发现自己每条需要连接同一个服务器无数次,那么长连接选项就是为你准备的:

ControlPersist 4h

现在你每次通过SSH与服务器建立连接之后,这条连接将被保持4个小时,即使在你退出服务器之后,这条连接依然可以重用,因此,在你下一次(4小时 之内)登录服务器时,你会发现连接以闪电般的速度建立完成,这个选项对于通过scp拷贝多个文件提速尤其明显,因为你不在需要为每个文件做单独的认证了。

3. 别再输入密码

如果你还在通过密码方式登录SSH,那么你或许应该试试SSH Keys,首先使用OpenSSH为自己声称一对密钥:

$ ssh-keygen

跟随指示,完成之后,你应该可以在你的.ssh目录下看到两个文件,id_rsa就是你的私钥,而id_ras.pub则是你的公钥,现在你需要将你的公钥拷贝到服务器上,如果你的系统有ssh-copy-id命令,拷贝会很简单:

$ ssh-copy-id smylers@compo.example.org

否则,你需要手动将你的私钥拷贝的服务器上的~/.ssh/authorized_keys文件中:

$ < ~/.ssh/id_rsa.pub ssh clegg.example.org ‘mkdir -p .ssh; cat >> .ssh/authorized_keys; chmod go-w .ssh .ssh/authorized_keys’

现在试试重新连接到SSH服务器,或是拷贝文件,是不是已经不需要再输入密码了?

为Putty配置SSH Key

Putty也可以使用SSH Key,从Putty网站下载PuttyGen和Pageant,然后使用PuttyGen生成你的密钥,将公钥拷贝到服务器的’.ssh/authorized_keys’目录,然后运行Pageant,导入你的私钥,让它在后台运行,险隘你就可以使用Putty通过公钥直接登录服务器了,你可以在Putty手册的第8,9章了解关于这一特性的详细介绍。

4. 连接中转

有时候你可能需要从一个服务器连接另外一个服务器,比如在两个服务器之间直接传输数据,而不用通过本地电脑中转:

www1 $ scp -pr templates www2:$PWD

(顺便说一下,当你需要在两台服务器间拷贝文件时,$PWD变量时非常有用的),因为即使你已经在两台服务器上添加了你本地电脑的公钥,scp默认 仍然会提示你输入密码:这是因为你用来作为跳板的那台服务器上并没有你的私钥,所以,第二胎服务器会拒绝你的公钥,但是一定不要通过将你的私钥拷贝到中转 服务器上来解决这个问题,你可以使用agent forwarding来解决这个问题,只要在你的.ssh/config文件中加入下面这行代码就可以了:

ForwardAgent yes

或者是在Putty中勾上“Allow agent forwarding”选项,现在你的本地SSH就变成了第一台服务器的SSH代理,从第一台服务器在连接其它服务器就变和和在你本地一样简单,注意,如果要开启这个选项,前提是这个中间服务器值得你信任。

5. 省略主机名

输入服务器的完整主机名来建立一个新的SSH连接实在是太乏味无聊了,尤其是当你有一组拥有相同域名但是子域名不同的服务器需要管理时,比如下面这样:

* www1.example.com
* www2.example.com
* mail.example.com
* intranet.internal.example.com
* backup.internal.example.com
* dev.internal.example.com

或许你的网络已经配置了可以直接使用短域名,比如intranet,但是如果你的网络不支持,实际上你可以自己搞定这个问题,而不用求助网络管理员。

解决办法根据你用的操作系统而略有差异,下面是我的Ubuntu系统的配置:

prepend domain-search “internal.example.com”, “example.com”;

然后你需要重启网络:$ sudo restart network-manager

不同的系统,这两条命令可能会略有差异。

5. 主机别名

你也可以在你的SSH配置中直接定义主机别名,就像下面这样:

Host dev
HostName dev.internal.example.com

你还可以使用通配符来进行分组:

Host dev intranet backup
HostName %h.internal.example.com

Host www* mail
HostName %h.example.com

在Putty中你可以为每个主机名保存单独的session,然后双击建立连接(但是它可能没办法支持通配符)。

7. 省去用户名

如果你在远程服务器上的用户名和你本地的用户名不同,你同样可以在SSH配置中进行设置:

Host www* mail
HostName %h.example.com
User simon

现在就算我的本地用户名是 smylers,我仍然可以这样连接我的服务器:

$ ssh www2

SSH会使用simon账户连接你的服务器,同样,Putty可以保存这个信息在你的session中。

8. 在服务器间跳转

有些时候,你可能没法直接连接到某台服务器,而需要使用一台中间服务器进行中转,这个过程也可以自动化。首先确保你已经为服务器配置了公钥访问,并开启了agent forwarding,现在你就可以通过2条命令来连接目标服务器,不会有任何提示输入:

$ ssh gateway
gateway $ ssh db

然后在你的本地SSH配置中,添加下面这条配置:

Host db
HostName db.internal.example.com
ProxyCommand ssh gateway netcat -q 600 %h %p

现在你就可以通过一条命令来直接连接目标服务器了:

$ ssh db

这里你可能会需要等待长一点的时间,因为SSH需要进行两次认证,,注意netcat也有可能被写成nc或者ncat或者前面还需要加上g,你需要检查你的中间服务器来确定实际的参数。

9. 突破网络封锁

有些时候,你使用的网络可能只开放了80端口,或者它们封锁了SSH端口(默认的22端口),这种情况下,你可以通过配置SSH服务器在80或者443端口进行监听来突破封锁,只需要编辑你的服务器的/etc/ssh/sshd_config文件:

Port 443

然后重启SSH服务器:

$ sudo reload ssh

当然这样做的前提是你的服务器没有使用HTTS服务,但是实际上你只需要设置一台服务器使用https端口就够了,你但你可以访问这台服务器,你就 可以使用我们前面提到的技术利用它作为跳板来访问其它服务器,但是记住,你需要提前配置好这台服务器(现在怎么样?),这样万一当你身处一个只能访问 Web的网络环境时,就可以省掉打电话让其他人帮你配置中间服务器的麻烦了。

10. 穿越Web代理

有些时候,你所在的网络不止封锁SSH端口,它们有可能更进一步,只让你通过Web代理来访问网络,幸运的是我们有一个叫做Corkscrew的程序可以通过Web代理在发送SSH数据。Corkscrew的使用非常简单,一般我都是在需要时搜索,然后直接下载,跟随网站上的指示,然后就搞定了,一般你需要这样一条配置:

ProxyCommand corkscrew proxy.example.org 8080 %h %p

11. 远程GUI

有时候通过本地的GUI程序来访问远程服务器的文件会非常有用,比如,编辑一副图片,或者查看一个PDF文件,或者只是简单的通过一个非命令行的编 辑器来修改代码,我发现GVim要比终端里的Vim更有用,因为我可以通过gvimopens打开一个新窗口来编辑文件,而用当前的SSH窗口继续执行其 它操作,不要要这样做,你需要先在你的SSH配置中开启一个叫做X forwarding的选项:

ForwardX11 yes

这个选项需要服务器配置才能起作用,服务器也需要开启X forwarding,你可以在服务器的/etc/ssh/sshd_config中添加下面这个命令:

X11Forwarding yes

同时你还需要确保安装了xauth,编辑器,图片查看器以及其它的你需要运行的图形化程序,这种方式只有在支持本地X服务器的操作提供才可以工 作,mac和Windows上都有免费的X Server,你可能需要花些时间配置它们,相比之下,切换到Linux相对会更容易一下。

12.本地操作远程文件

另一种让远程GUI程序显示在本地的替代方案就是让本地的GUI程序可以直接操作远程文件,你可以通过SSHFS来实现,只需要创建一个空目录,然后使用SSHFS将一个远程目录mount到这个目录就可以了:

$ mkdir gallery_src
$ sshfs dev:projects/gallery/src gallery_src
$ cd gallery_src
$ ls

现在你就可以使用任何你喜欢的本地程序来便捷这个目录中的文件了,它们看起来是在你的本地,但其实时远程服务器上的文件,你可以使用fusermount命令来unmount这些文件,不要担心记不住,它们就在sshfs手册的顶上:

$ cd ..
$ fusermount -u gallery_src

SSHFS可以在Linux和OSX上工作,Windows用户我目前还没找到什么好办法。

13. 通过Vim访问远程文件

Vim有一个内置的功能可以直接编辑远程文件,需要借助SCP URL:

$ gvim scp://dev/projects/gallery/src/templates/search.html.tt

这中方式明显不如SSHFS灵活,但是如果你只需要对远程服务器的1,2个文件进行编辑时,这条命令就要更灵活一些了,并且可以在Windows上你也可以这样做:

:help netrw-problems

14. 使用本地App连接远程服务器

有时可能有些服务,比如数据库或是Web服务器,它们运行在远程服务器上,但是如果有用方式可以直接从本地程序连接它们,那会非常有用,要做到这一 点,你需要用到端口转发(port forwarding),举个例子,如果你的服务器运行Postgres(并且只允许本地访问),那么你就可以在你的SSH配置中加入:

Host db
LocalForward 5433 localhost:5432

现在当你连接你的SSH服务器时,它会在你本地电脑打开一个5433端口(我随便挑的),并将所有发送到这个端口的数据转发到服务器的5432端口 (Postgres的默认端口),然后,只要你和服务器建立了连接,你就可以通过5433端口来访问服务器的Postgres了。

$ ssh db

现在打开另外一个窗口,你就可以通过下面这条命令在本地连接你的Postgres数据库了:

$ psql -h localhost -p 5443 orders

如果你想要使用服务器不支持的图形化Postgres客户端时,这条命令会显得尤其有用:

$ pgadmin3 &

或者你有一个后台的Web服务器,你不希望直接通过Internet访问它,你也可以通过端口转发来访问它:

Host api
LocalForward 8080 localhost:80

现在连接到服务器:

$ ssh api

然后将浏览器指向你选择的端口号:

$ firefox http://localhost:8080/

15. 减少延迟

如果每次连接服务器都意味着你需要等待几十秒而无所事事,那么你或许应该试试在你的SSH配置中加入下面这条:

GSSAPIAuthentication no

如果这条命令有效的话,你应该通知你的系统管理员让他在服务器上禁用这个选项,这样其他人就不用再分别添加这条配置到它们的本地配置了。

16. 加速连接

如果你确保你和某个服务器之间的连接是安全的(比如通过公司内网连接),那么你就可以通过选择arcfourencryption算法来让数据传输更快一些:

Host dev
Ciphers arcfour

注意这个加速是以牺牲数据的“加密”性为代价的,所以如果你连接的是位于网上的服务器,千万不要打开这个选项,并且确保你是通过VPN建立的连接。

开始行动吧!

Posted in Uncategorized

每个程序员都必须遵守的编程原则

好的编程原则跟好的系统设计原则和技术实施原则有着密切的联系。下面的这些编程原则在过去的这些年里让我成为了一名优秀的程序员,我相信,这些原则对任何一个开发人员来说,都能让他的编程能力大幅度的提高,能让他开发出可维护性更强、缺陷更少的程序。

我不要自我重复 — 这也许是在编程开发这最最基本的一个信条,就是要告诉你不要出现重复的代码。我们很多的编程结构之所以存在,就是为了帮助我们消除重复(例如,循环语句, 函数,类,等等)。一旦程序里开始有重复现象的出现(例如很长的表达式、一大堆的语句,但都是为了表达相同的概念),你就需要对代码进行一次新的提炼,抽 象。
http://en.wikipedia.org/wiki/Don%27t_repeat_yourself

提炼原则 — 跟“不要自我重复原则”相关,这一原则是说“程序中任何一段具有功能性的代码在源代码文件中应该唯一的存在。”
http://en.wikipedia.org/wiki/Abstraction_principle_(programming)

保持简单 — 简单化(避免复杂)永远都应该是你的头等目标。简单的程序让你写起来容易,产生的bug更少,更容易维护修改。
http://en.wikipedia.org/wiki/KISS_principle

不要开发你目前用不到的功能 — 除非你真正需要用到它,否则不要轻易加上那些乱七八糟用不到的功能。
http://en.wikipedia.org/wiki/YAGNI

用最简单的方法让程序跑起来 — 在开发时有个非常好的问题你需要问问自己,“怎样才能最简单的让程序跑起来?”这能帮助我们在设计时让程序保持简单。
http://c2.com/xp/DoTheSimplestThingThatCouldPossiblyWork.html

不要让我动脑子 — 这实际上是Steve Krug 关于web界面操作的一本书的书名,但也适用于编程。主旨是,程序代码应该让人们花最小的努力就能读懂和理解。如果一段程序对于阅读者来说需要花费太多的努力才能理解,那它很可能需要进一步简化。
http://www.sensible.com/dmmt.html

开放/封闭原则 — 程序里的实体项(类,模块,函数等)应该对扩展行为开放,对修改行为关闭。换句话说,不要写允许别人修改的类,应该写能让人们扩展的类。
http://en.wikipedia.org/wiki/Open_Closed_Principle

为维护者写程序 — 任何值得你编写的程序在将来都是值得你去维护的,也许由你维护,也许由他人。在将来,当你不得不维护这些程序时,你对这些代码的记忆会基本上跟一个陌生人 一样,所以,你最好还是当成一直在给别人写程序。一个有助于你记住这个原则的办法是“写程序时时刻记着,这个将来要维护你写的程序的人是一个有严重暴力倾 向,并且知道你住在哪里的精神变态者”。
http://c2.com/cgi/wiki?CodeForTheMaintainer

最少意外原则 — 最少意外原则通常是使用在用户界面设计上,但这个原则同样适用于编写程序。程序代码应尽可能的不要让阅读者感到意外。也就是说应该遵循编码规范和常见习惯,按照公认的习惯方式进行组织和命名,不符常规的编程动作应该尽可能的避免。
http://en.wikipedia.org/wiki/Principle_of_least_astonishment

单一职责原则 — 一个代码组件(例如类或函数)应该只执行单一的预设的任务。
http://en.wikipedia.org/wiki/Single_responsibility_principle

最小化耦合关系 — 一个代码片段(代码块,函数,类等)应该最小化它对其它代码的依赖。这个目标通过尽可能少的使用共享变量来实现。“低耦合是一个计算机系统结构合理、设计优秀的标志,把它与高聚合特征联合起来,会对可读性和可维护性等重要目标的实现具有重要的意义。”
http://en.wikipedia.org/wiki/Coupling_(computer_programming)

最大化内聚性 — 具有相似功能的代码应该放在同一个代码组件里。
http://en.wikipedia.org/wiki/Cohesion_(computer_science)

隐藏实现细节 — 隐藏实现细节能最小化你在修改程序组件时产生的对那些使用这个组件的其它程序模块的影响。
http://en.wikipedia.org/wiki/Information_Hiding

笛米特法则(Law of Demeter) — 程序组件应该只跟它的直系亲属有关系(例如继承类,内包含的对象,通过参数入口传入的对象等。)
http://en.wikipedia.org/wiki/Law_of_Demeter

避免过早优化 — 只有当你的程序没有其它问题,只是比你预期的要慢时,你才能去考虑优化工作。只有当其它工作都做完后,你才能考虑优化问题,而且你只应该依据经验做法来优 化。“对于小幅度的性能改进都不该考虑,要优化就应该是97%的性能提升:过早优化是一切罪恶的根源”—Donald Knuth。
http://en.wikipedia.org/wiki/Program_optimization

代码复用 — 这不是非常核心的原则,但它跟其它原则一样非常有价值。代码复用能提高程序的可靠性,节省你的开发时间。
http://en.wikipedia.org/wiki/Code_reuse

职责分离 — 不同领域的功能应该由完全不同的代码模块来管理,尽量减少这样的模块之间的重叠。http://en.wikipedia.org/wiki/Separation_of_concerns

拥抱变化 — 这是Kent Beck的一本书的副标题,它也是极限编程和敏捷开发方法的基本信条之一。很多的其它原则都基于此观念:面对变化,欢迎变化。事实上,一些经典的软件工程 原则,例如最小化耦合,就是为了让程序更容易面对变化。不论你是否采用了极限编程方法,这个原则对你的程序开发都有重要意义。http://www.amazon.com/gp/product/0321278658

Posted in Uncategorized

不要自称为程序员

每年都有无数年轻程序员,加入软件行业。

 

他们在学校里学过编程,但是对这个行业的现实一无所知。

 

Patrick McKenzie是美国一家小软件公司的老板,他写了一篇长文,介绍这个行业的一些实际情况。我看了以后很感慨,有些地方很受启发。我选择了一部分,翻译如下。

 

一、90%的编程工作来自内部软件

 

(90% of programming jobs are in creating Line of Business software)

 

计算机专业的学生,可能有一种印象,觉得大部分程序员,都在编写公开出售的软件或者通用软件。

 

这种看法是不对的。大部分程序员,实际上编写的是不公开的企业内部软件,比如追踪费用的软件、优化装运成本的软件、帮助记账的软件、设计新部件的软件、计算保单价格的软件、识别恶意订单的软件等等。

 

各种各样的商业公司,开发内部软件,解决它们自己的问题。市场上对程序员的大部分需求来源于此,只有极少数程序员直接编写面向外部顾客的软件。

 

内部软件的开发,通常非常乏味,令人厌倦。因为它们的技术复杂性低、技术决策非常保守、预算很少、缺乏长远考虑。但是,世界上大部分编程工作都是这种。

 

二、别人雇你的目的,是让你创造利润,不是让你编程

 

(Engineers are hired to create business value, not to program things)

 

商业公司最关心的(或者说唯一在乎的)事情,就是增加收入、降低成本。因此,它们实际上需要的不是程序员,而是能够帮助它们增加收入、降低成本的人。

 

开发优美的软件,解决技术难题,编写没有bug的代码,这些都不是商业公司的目的。它们雇佣你,是为了让你帮它们完成某个可以增加收入、降低成本的项目,而不是因为你是geek。

 

你个人对于公司的唯一价值,就在于你能多大程度上为它们增加收入、降低成本。

 

三、不要自称为程序员

 

(Don’t call yourself a programmer)

 

很多公司的经理不懂计算机,在他们心目中,”程序员”就是一群高成本的劳动力,只会在一台复杂的机器上干一些难懂的事情。

 

如果你自称为”程序员”,当公司需要压缩成本的时候,某些经理首先就会想到解雇你。有一家公司叫Salesforce,口号是”没有软件”,意思就是如果经理们购买了他们的服务,就不再需要别的软件管理销售业务了,也就是说,不再需要自己雇佣程序员了。

 

正确的做法是,你应该把自己描述成与增加收入、降低成本有关系的人,比如”xx产品的开发者”或”改进者”。有一个Google Adsense程序员的自我介绍,是这样写的:”Google公司97%的收入,与我的代码有关。”

 

四、不要限定自己

 

(You are not defined by your chosen software stack)

 

年轻学生经常会问,应该选择哪种语言或平台?学会Java,是不是比学会.NET容易找工作?

 

过分强调某一种语言或平台,都是不必要的。如果你把自己限定为Java程序员或.NET程序员,你就已经输了,因为首先你不应该自称为程序员(理由见上一点),其次这种限定使得你自动被排除在世界上大多数编程工作之外。

 

现实生活中,学会一种新语言,只需要几个星期,然后再过半年到一年,你就会变成老手。那时,根本没人在乎你以前用什么语言。

 

天才程序员是很少的,可是需要天才程序员的工作机会却很多很多,大多数场合都是需求远远大于供给。这意味着,即使你不是天才程序员,只要你是一个优 秀工程师,那些招聘公司也会立刻录用你,因为它们知道招聘到天才程序员的机会微乎其微。(重复一遍,所谓”优秀工程师”,就是你的履历上有一连串增加收 入、降低成本的记录。)

 

某些公司的人事部门,会根据某个关键词(比如Java或.NET)过滤简历。虽然这样的公司根本不值得去,但是如果你真的想过这一关,也很容易:投入几个晚上和周末,在你当前的项目中设法用到这个关键词,然后再把它写进简历就行了。

 

五、如何提高求职时的谈判能力?

 

(How do I become better at negotiation?)

 

(1)记住你不是在求职,不是在展示编程技巧,而是在推销某种商业需求(增加收入或降低成本)的解决方案。

 

(2)面试时,要有自信,要平等的对话。你要的是一个互利的录用合同,不要每次对方提出要求,你都说Yes。

 

(3)雇主可能会问”你的上一份工资是多少”,他们其实在说”给我一个理由,压低你的报酬”。你要想好如何适当地回答这个问题。

 

(4)要还价。这里不仅仅指钱,还指其它你关心的方面。如果你无法要求更高的薪水,那就试着要求更多的假期。

 

(5)在对方决定录用你以后,才开始讨论薪水。因为那时,他们已经在你身上,投入了大量的时间和金钱,产生了一定的成本,此时他们可能觉得一些小问题已经不值得再纠缠了,比如每年的工资增加几千元。

 

六、创业公司是否适合应届毕业生?

 

(Are startups great for your career as a fresh graduate?)

 

如果你一毕业就加入创业公司,最可能的结果是,接下来几年你都工作得非常辛苦,然后公司悲惨地失败了,你失业了,不得不又去另一家创业公司工作。

 

如果你真的想去创业公司,应该首先找一家大公司干上两年,攒一点钱,积累一些经验,然后精心挑选后再去创业公司。

 

在创业公司工作,一般情况下,你遇到的都是创业者。他们大多数人没有能力在两年后雇佣你;而在大公司工作,你遇到的都是其他大公司的人,他们中很多人将来有能力雇用你或者帮你介绍工作。

 

七、在创业公司工作是否值得推荐?

 

(So would you recommend working at a startup? )

 

选择创业公司,就是选择一条职业道路,而不是选择一种生活方式。可惜很多人把这两者颠倒了,他们推荐创业公司,实际上是在推荐一种你感兴趣的生活方式。

 

如果你确实喜欢这种生活方式,老实说,你在大公司里也可以得到它们。在许许多多大公司里,你都有机会钻研最新的技术,而且还能5点半准时回家照顾孩子。

 

八、沟通技能是最重要的职业技能

 

(Your most important professional skill is communication)

 

前面说过,工程师被雇佣,不是因为会编程,而是因为能够创造商业价值。所以,你让人们相信你能创造价值,这是帮助你找到工作的最重要的能力。这种能力与你真的能创造多少价值,实际上联系不是很紧密。

 

我认识的一些最优秀的程序员,往往拙于表达。因此,别人不是不想与他们一起工作,就是低估了他们的价值。相反地,如果你看上去很会编程,并且很善于表达,别人就会真的这样看待你。

Posted in Uncategorized

大型网站架构不得不考虑的10个问题

这里的大型网站架构只包括高互动性高交互性的数据型大型网站,基于大家众所周知的原因,我们就不谈新闻类和一些依靠HTML静态化就可以实现的架构 了,我们以高负载高数据交换高数据流动性的网站为例,比如海内,开心网等类似的web2.0系列架构。我们这里不讨论是PHP还是JSP或者.NET环 境,我们从架构的方面去看问题,实现语言方面并不是问题,语言的优势在于实现而不是好坏,不论你选择任何语言,架构都是必须要面对的。

这里讨论一下大型网站需要注意和考虑的问题。

1、海量数据的处理

众所周知,对于一些相对小的站点来说,数据量并不是很大,select和update就可以解决我们面对的问题,本身负载量不是很大,最多再加几个 索引就可以搞定。对于大型网站,每天的数据量可能就上百万,如果一个设计不好的多对多关系,在前期是没有任何问题的,但是随着用户的增长,数据量会是几何 级的增长的。在这个时候我们对于一个表的select和update的时候(还不说多表联合查询)的成本的非常高的。

2、数据并发的处理

在一些时候,2.0的CTO都有个尚方宝剑,就是缓存。对于缓存,在高并发高处理的时候也是个大问题。在整个应用程序下,缓存是全局共享的,然而在 我们进行修改的时候就,如果两个或者多个请求同时对缓存有更新的要求的情况下,应用程序会直接的死掉。这个时候,就需要一个好的数据并发处理策略以及缓存 策略。

另外,就是数据库的死锁问题,也许平时我们感觉不到,死锁在高并发的情况下的出现的概率是非常高的,磁盘缓存就是一个大问题。

3、文件存贮的问题

对于一些支持文件上传的2.0的站点,在庆幸硬盘容量越来越大的时候我们更多的应该考虑的是文件应该如何被存储并且被有效的索引。常见的方案是对文 件按照日期和类型进行存贮。但是当文件量是海量的数据的情况下,如果一块硬盘存贮了500个G的琐碎文件,那么维护的时候和使用的时候磁盘的Io就是一个 巨大的问题,哪怕你的带宽足够,但是你的磁盘也未必响应过来。如果这个时候还涉及上传,磁盘很容易就over了。

也许用raid和专用存贮服务器能解决眼下的问题,但是还有个问题就是各地的访问问题,也许我们的服务器在北京,可能在云南或者新疆的访问速度如何解决?如果做分布式,那么我们的文件索引以及架构该如何规划。

所以我们不得不承认,文件存贮是个很不容易的问题

4、数据关系的处理

我们可以很容易的规划出一个符合第三范式的数据库,里面布满了多对多关系,还能用GUID来替换INDENTIFY COLUMN 但是,多对多关系充斥的2.0时代,第三范式是第一个应该被抛弃的。必须有效的把多表联合查询降到最低。

5、数据索引的问题

众所周知,索引是提高数据库效率查询的最方面最廉价最容易实现的方案。但是,在高UPDATE的情况下,update和delete付出的成本会高的无法想想,笔者遇到过一个情况,在更新一个聚焦索引的时候需要10分钟来完成,那么对于站点来说,这些基本上是不可忍受的。

索引和更新是一对天生的冤家,问题A,D,E这些是我们在做架构的时候不得不考虑的问题,并且也可能是花费时间最多的问题。

6、分布式处理

对于2.0网站由于其高互动性,CDN实现的效果基本上为0,内容是实时更新的,我们常规的处理。为了保证各地的访问速度,我们就需要面对一个绝大的问题,就是如何有效的实现数据同步和更新,实现各地服务器的实时通讯有是一个不得不需要考虑的问题。

7、Ajax的利弊分析

成也AJAX,败也AJAX,AJAX成为了主流趋势,突然发现基于XMLHTTP的post和get是如此的容易。客户端get或者post 到服务器数据,服务器接到数据请求之后返回来,这是一个很正常的AJAX请求。但是在AJAX处理的时候,如果我们使用一个抓包工具的话,对数据返回和处 理是一目了然。对于一些计算量大的AJAX请求的话,我们可以构造一个发包机,很容易就可以把一个webserver干掉。

8、数据安全性的分析

对于HTTP协议来说,数据包都是明文传输的,也许我们可以说我们可以用加密啊,但是对于G问题来说的话,加密的过程就可能是明文了(比如我们知道 的QQ,可以很容易的判断他的加密,并有效的写一个跟他一样的加密和解密方法出来的)。当你站点流量不是很大的时候没有人会在乎你,但是当你流量上来之 后,那么所谓的外挂,所谓的群发就会接踵而来(从qq一开始的群发可见端倪)。也许我们可以很的意的说,我们可以采用更高级别的判断甚至HTTPS来实 现,注意,当你做这些处理的时候付出的将是海量的database,io以及CPU的成本。对于一些群发,基本上是不可能的。笔者已经可以实现对于百度空 间和qq空间的群发了。大家愿意试试,实际上并不是很难。

9、数据同步和集群的处理的问题

当我们的一台databaseserver不堪重负的时候,这个时候我们就需要做基于数据库的负载和集群了。而这个时候可能是最让人困扰的的问题 了,数据基于网络传输根据数据库的设计的不同,数据延迟是很可怕的问题,也是不可避免的问题,这样的话,我们就需要通过另外的手段来保证在这延迟的几秒或 者更长的几分钟时间内,实现有效的交互。比如数据散列,分割,内容处理等等问题。

10、数据共享的渠道以及OPENAPI趋势

Openapi已经成为一个不可避免的趋势,从google,facebook,myspace到21kaiyun.com,都在考虑这个问题,它 可以更有效的留住用户并激发用户的更多的兴趣以及让更多的人帮助你做最有效的开发。这个时候一个有效的数据共享平台,数据开放平台就成为必不可少的途径 了,而在开放的接口的情况保证数据的安全性和性能,又是一个我们必须要认真思考的问题了。

Posted in Uncategorized

/usr 的来龙去脉

在 linux 文件结构中,有一个很神奇的目录 —— /usr。之前一直没有怎么关注过它,反正程序都是安装在里边的,也没有什么值得追根溯源的东西。直到有一天 fedora 要简化整个文件系统体系,看到讨论才想到,usr 到底是什么的缩写呢,它又是怎么来的呢?

讨论中,大部分观点认为:

  • usr 是 unix system resources 的缩写;
  • usr 是 user 的缩写;
  • usr 是 unix software resources 的缩写。

根据常识判断,是 user 缩写的可能性不大,因为和 /home 冲突了嘛。不过是 system resources 还是 software resources 的缩写还真不好说。特此查了好多东西,却发现竟然连 wikipedia 也模棱两可

后来终于找到了 相关的文档和介绍。(viacache

/usr usually contains by far the largest share of data on a system. Hence, this is one of the most important directories in the system as it contains all the user binaries, their documentation, libraries, header files, etc…. X and its supporting libraries can be found here. User programs like telnet, ftp, etc…. are also placed here. In the original Unix implementations, /usr was where the home directories of the users were placed (that is to say, /usr/someone was then the directory now known as /home/someone). In current Unices, /usr is where user-land programs and data (as opposed to ’system land’ programs and data) are. The name hasn’t changed, but it’s meaning has narrowed and lengthened from “everything user related” to “user usable programs and data”. As such, some people may now refer to this directory as meaning ‘User System Resources’ and not ‘user’ as was originally intended.(via1,2

/usr 是系统核心所在,包含了所有的共享文件。它是 unix 系统中最重要的目录之一,涵盖了二进制文件,各种文档,各种头文件,x,还有各种库文件;还有诸多程序,例如 ftp,telnet 等等。

曾经的 /usr 还是用户的家目录,存放着各种用户文件 —— 现在已经被 /home 取代了(例如 /usr/someone 已经改为 /home/someone)。现代的 /usr 只专门存放各种程序和数据,用户目录已经转移。虽然  /usr 名称未改,不过其含义已经从“用户目录”变成了“unix 系统资源”目录。值得注意的是,在一些 unix 系统上,仍然把 /usr/someone 当做用户家目录,如 Minix。

至此,真相大白。看来就像前一阵子的 /var/run 移到 /run 一样。

真的是不看不知道,一看吓一跳呀。原来 linux 几经进化,好多目录的诞生和用途已经产生了根本的变化。历史车轮在前进,长江后浪推前浪,正所谓:学习历史,收获真知;尽心竭力,前进不止。

附录:/usr 目录结构

  • /usr/bin : 所有可执行文件,如 gcc,firefox 等(指不包含在 /sbin 和 /bin 内的);
  • /usr/include : 各种头文件,编译文件等时需要使用;
    • /usr/include/’package-name’ : 程序特定的头文件;
  • /usr/lib : 所以可执行文件所需要的库文件;
  • /usr/local : /usr 通常只包含系统发行时自带的程序,而 /usr/local 则是本地系统管理员用来自由添加程序的目录;
  • /usr/X11R6 : x 系统的二进制文件,库文件,文档,字体等。它不等同于 /usr 的作用,只有 x 才能调用这些库文件等,其他程序不读取或者使用。因为 linux 没有原生图形界面,而且 linux 大部分情况下是 for server 的,所以图形界面没有意义;其中 X11R6 代表 version 11 release 6;
    • /usr/X11R6/bin : x 的二进制文件,包含运行 x 的必须文件;
    • /usr/X11R6/include : x 相关的头文件;
    • /usr/X11R6/lib : x 库文件;
    • /usr/X11R6/lib/modules : x 的模块,启动时加载。缺少 video4linux, DRI and GLX 和 输入输出设备 模块,将工作不正常;
    • /usr/X11R6/lib/X11/fonts : x font server 的字体文件;
  • /usr/doc : 文档。实际是 /usr/share/doc 的软链接;
  • /usr/etc : 一个极少用到的配置文件存放地;
  • /usr/games : 曾经包含游戏等文件,现在很少用到;
  • /usr/info : 系统相关信息,是 /usr/share/info 的软链接;
  • /usr/man : man 手册,已经移至 /usr/share/man
  • /usr/sbin : 类似 /sbin,root 可以执行。但此目录不包含在环境变量 $PATH 中,它包含的程序类似于 chroot, useradd, in.tftpd and pppconfig;
  • /usr/share : 它包含了各种程序间的共享文件,如字体,图标,文档等。(/usr/local 对应的目录是  /usr/loca/share);
    • /usr/share/doc : 类似应用程序的 man 手册。它包含程序的说明文件,默认配置文件等;
    • /usr/share/info : 不常用,已经被 man 代替;
    • /usr/share/man : app 的 manual;
    • /usr/share/icons : 应用程序的图标等文件,分为 png,svg 等多种格式;
    • /usr/share/fonts : 字体文件,系统范围内可使用,~/.fonts 仅当前用户可用;
  • /usr/src : linux 内核的源码和说明文档等;
    • /usr/src/linux : linux 源代码;
    • /usr/src/linux/.config : 内核编译过程产生的文件;通常由命令 ‘make config’ , ‘make menuconfig’ 或 ‘make xconfig’ 执行后产生;
    • /usr/src/linux/.depend, /usr/src/linux/.hdepend : ‘make dep’ 检测编译依赖时需要的文件,由 /usr/src/linux/.config 产生;
    • /usr/src/linux/COPYING : GNU license;
    • /usr/src/linux/Makefile : 编译内核所需的 Makefile;
    • /usr/src/linux/Rules.make : 当有多个 Makefile 时,根据它的规则执行 make;
  • /usr/tmp : 已经被众多发行版抛弃的临时文件夹。
Posted in Uncategorized

ruby-debug in 30 seconds (we don't need no stinkin' GUI!)

Many people (including me) have complained about the lack of a good GUI debugger for Ruby. Now that some are finally getting usable, I've found I actually prefer IRB-style ruby-debug to a GUI.

There’s good tutorial links on the ruby-debug homepage, and a very good Cheat sheet, but I wanted to give a bare-bones HOWTO to help you get immediately productive with ruby-debug.

Install the latest gem

$ gem install ruby-debug 

Install the cheatsheet

$ gem install cheat $ cheat rdebug 

Set autolist, autoeval, and autoreload as defaults

$ vi ~/.rdebugrc set autolist set autoeval set autoreload 

Run Rails (or other app) via rdebug

$ rdebug script/server 

Breakpoint from rdebug

(rdb:1) b app/controllers/my_controller.rb:10 

Breakpoint in source

require 'ruby-debug' debugger my_buggy_method('foo') 

Catchpoint

(rdb:1) cat RuntimeError 

Continue to breakpoint

(rdb:1) c 

Next Line (Step Over)

(rdb:1) n 

Step Into

(rdb:1) s 

Continue

(rdb:1) c 

Where (Display Frame / Call Stack)

(rdb:1) where 

List current line

(rdb:1) l= 

Evaluate any var or expression

(rdb:1) myvar.class 

Modify a var

(rdb:1) @myvar = 'foo' 

Help

(rdb:1) h 

There are many other commands, but these are the basics you need to poke around. Check the Cheat sheet for details.

This can also be used directly from any IDE that supports input into a running console (such as Intellij Idea).

That should get you started. So, before you stick in another ‘p’ to debug, try out ruby-debug instead!

require 'rubygems'
require 'ruby-debug'
#$ruby breakpoint_test.rb
#vim breakpoint_test.rb
#:!ruby breakpoint_test.rb
#Next Line (Step Over)
#(rdb:1) n
#Step Into
#(rdb:1) s
#to debug in a function which is called from other place,before this function call,type 's' and you will found your are inside this function.
def leap_year year
leap = case
breakpoint
when year % 400 == 0: true
when year % 100 == 0: false
else year % 4 ==0
end
puts leap
end
if __FILE__ == $0
# tests...
puts "year=2000"
leap_year 2000
puts "year=2004"
leap_year 2004
puts "year=2002"
leap_year 2002
end

标签: breakpoint debug rails ruby shell

Posted in Uncategorized