'Rails2.1'에 해당되는 글 3건

  1. [2008/07/02] Rails 2.1 : ActiveSupport::Cache
  2. [2008/04/16] Rails 2.1 : Dirty Objects
  3. [2008/04/04] Rails 2.1 : Gem Dependencies (1)

Rails 2.1 : ActiveSupport::Cache

[Development]

원문(http://inocrazy.com/docs/10)에서 좀 더 깔끔하게 보실 수 있습니다.

개요

Rails 2.1에서는 ActiveSupport::Cache 모듈이 추가되면서 간편하게 cache를 설정하고 사용하는 것이 가능해졌다. cache를 실제로 저장하고 처리하는 caching store도 여러가지가 제공되므로 자신의 편의에 맞는 것을 사용할 수 있게 되었다. 이번 문서에서는 Rails의 새로운 Cache 기능에 대해서 자세히 살펴보자.



ActiveSupport::Cache::Store

ActiveSupport::Cache에서 가장 중요한 클래스는 Store 클래스이다. 이 클래스는 다양한 caching store를 위한 인터페이스 역할을 한다. FileStore, MemCacheStore 등의 클래스가 이 클래스를 상속해서 실질적인 처리를 구현하고 있다. Store 클래스의 대표적인 인스턴스 메소드는 다음과 같다.

메소드 내용
read(key, options = nil) key에 해당하는 값을 읽어온다.
write(key, value, options = nil) key에 해당하는 값을 저장한다.
fetch(key, options = nil) key에 해당하는 값이 저장되어 있으면 읽어오고, 값이 없을 경우 전달되는 block을 실행시킨 결과를 저장 후 리턴한다.
delete(key. options = nil) key에 해당하는 값을 삭제한다.
delete_matched(matcher, options = nil)                  정규식 matcher와 matching되는 결과만을 삭제한다. MemCacheStore에서는 구현되어 있지 않다.
exist?(key, options = nil) key에 해당하는 값이 존재하는지 여부를 리턴한다.
increment(key, amount = 1) key에 해당하는 값이 존재하는 경우, amount만큼 증가시킨다.
decrement(key, amount = 1) key에 해당하는 값이 존재하는 경우, amount만큼 감소시킨다.

어플리케이션 개발 시에 cache의 처리 상황을 파악하기 쉽도록, 각 메소드가 실행되는 경우 debug 수준의 로그를 남기게 된다. 따라서 처리된 결과값이 cache로부터 가져온 것인지, 혹은 DB를 access해서 가져온 것인지를 모니터링하면서 개발을 진행할 수 있다.


또한 ActiveSupport::Cache에는 ThreadSafety라는 모듈이 선언되어 있다. 모듈명에서도 알 수 있듯이 이 모듈은 thread safety를 위해서, read, write, delete 메소드를 Mutex#synchronize 메소드로 감싸는 wrapping 메소드를 제공한다. caching store에서 thread safety를 가능하게 하기 위해서는 Store#threadsafe! 메소드를 실행하면 된다.


위의 기본적인 CRUD 관련 메소드뿐만 아니라, 두 개의 클래스 메소드도 제공한다. lookup_store(*store_option)은 인수로 전달된 option에 해당하는 caching store 인스턴스를 리턴한다. environment.rb의 config.cache_store 설정에서 내부적으로 사용되는 메소드이다. 사용가능한 인수들은 config.cache_store 설정을 살펴보면서 정리하자.


  1. new_cache = ActiveSupport::Cache.lookup_store(:file_store, 'tmp/new_cache')

또한 expand_cache_key(key, namespace = nil) 클래스 메소드는 전달된 key를 확장하게 된다. Store 클래스에서 각 cache는 결국 hash 형식으로 처리되게 된다. 따라서 여러가지 caching되는 값들이 중복되지 않기 위해서는 유일한 key를 필요로 하게 된다. 이를 위해서 이 메소드에서는 다음과 같은 형식으로 키를 확장한다.


key => [namespace/][RAILS_CACHE_ID or RAILS_APP_VERSION/]<cache_key or to_param>


각 파트들은 해당 값이 인수로 전달되거나 설정된 경우에 추가되게 된다. 세번째 파트에서 key가 :cache_key라는 메소드가 있는 경우, 해당 값을 설정하게 된다. ActiveRecord::Base에는 cache_key라는 메소드가 추가되어서 쉽게 caching 처리가 가능해졌다. (<model_name>/<id>-<updated_at> 형식) 만약 key가 Array로 전달된 경우는 모든 요소들에 대해서 expance_cache_key 메소드가 실행된 결과가 to_param 형식으로 리턴된다.



Caching Stores

Rails 2.1에서는 5개의 caching store을 제공한다. 각각은 다음과 같다.

Caching Store 내용
FileStore cache를 개별 파일에 저장하고 읽어온다.
MemoryStore cache를 hash 변수에 저장하고 읽어온다.
DRbStore 메모리 대신 DRb server에 cache를 사용하는 것을 제외하곤, MemoryStore와 동일하다.
MemCacheStore memcache를 사용하여 저장하고 읽어온다
CompressedMemCacheStore read/write 시에 Gzip을 이용해서 압축과 해제를 하는 것을 제외하곤, MemCacheStore와 동일하다.

위와 같이 5가지의 caching store를 자신의 환경에 맞게 선택해서 사용하는 것이 가능하다. 저장공간을 기준으로 나누었을 때, 크게 File, Memory, Shared Memory에 저장하는 경우로 나누어볼 수 있다.


FileStore

FileStore에서는 각각의 cache를 개별 파일에 저장하고 읽어오게 된다. 추가적인 config.cache_store 설정이 없을 경우, tmp/cache 디렉토리가 존재한다면 Rails 2.1에서는 기본적으로 FileStore를 기본 caching store로 설정하게 된다. 예를 들어, cache가 저장되는 곳이 tmp/cache이고, inocrazy=Crazy For Innovation! 이라는 key=value를 저장한다고 가정하면, 실제 cache는 tmp/cache/inocrazy.cache 파일에 "Crazy For Innovation!"이라는 값을 쓰게 된다.


FileStore의 장점은 추가적인 설정없이 간편하게 사용할 수 있다는 것이다. 반면 매번 cache를 읽고 쓸 때마다 File IO가 발생하게 되므로, 상대적으로 속도가 느리다. 또한 app. server가 여러 대인 경우, cache가 각 서버에 저장되므로 정상적으로 사용할 수 없다.


MemoryStore

MemoryStore는 일반적인 hash 변수에 cache를 저장하고 읽어온다. FileStore와 같이 간편하게 사용할 수 있고, 또한 FileStore에 비해 빠르다는 장점이 있다. 하지만 마찬가지로 여러 대의 app. server에서는 사용할 수 없다.


DRbStore

DRbStore는 cache 저장을 위해서 DRb server를 사용한다는 점을 제외하고는 MemoryStore와 동일하다. (실제로 MemoryStore를 상속받아서 구현되었다.) MemoryStore의 장점에, 분산된 app. server에서도 사용할 수 있다는 추가적인 장점을 가지고 있다.


MemCacheStore

memcache를 이용해서 cache를 처리한다. 여러 대의 memcache server를 이용해서 효율적인 caching 처리를 할 수 있다. Rails 2.1에서는 ActiveSupport에 memcache-client 1.5.0이 포함되므로써 추가적으로 gem을 설치할 필요가 없게 되었다.


CompressedMemCacheStore

CompressedMemCacheStore는 MemCacheStore를 상속하여 구현한 클래스로서, read/write 시에 ActiveSupport::Gzip을 이용하여 압축과 해제를 추가적으로 하게 된다.



MemCacheStore 자세히 살펴보기

MemCacheStore는 실제 서비스에서 가장 많이 사용되므로 여기서 좀 더 자세히 살펴보자.


MemCache 설정

MemCacheStore는 다음과 같이 서버 목록과 option들을 인수로 전달받는다.


  1. cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, '192.168.10.1:11211', '192.168.10.2:11212', :namespace => 'inocrazy')

memcache는 기본적으로 여러 대의 분산된 memcache server를 이용할 수 있으므로, 해당 서버들의 목록을 설정할 수 있다. 또한 각 서버의 weight를 설정함으로써 처리 빈도를 조절할 수 있다. 서버는 hostname[:port][:weight]와 같은 형식으로 설정한다.


또한 사용가능한 옵션들은 다음과 같다.

옵션 내용
:namespace cache의 namespace를 설정한다. memcache server는 여러 서비스가 함께 사용하게 되므로 서비스 간에 키의 중복이 발생할 수 있다. 이 namespace를 접두어로 붙임으로써, 유일한 키로 설정되도록 한다.
:readonly memcache를 읽기 전용으로 사용한다. 따라서 cache를 쓰려고 하는 경우, 예외를 발생시키게 된다.
:multithread thread safety를 위해서 cache access를 Mutex로 wrapping한다.
read/write 옵션

MemCacheStore에서 read/write 메소드의 경우, 다음과 같은 추가적인 옵션을 사용할 수 있다.

옵션 내용
:raw memcache-client에서는 값을 저장하고 가져오는 경우, Marshal#dump와 Marshal#load 메소드를 사용한다. 만약 :raw가 true로 설정되게 되면, marshaling되지 않은 raw value로 저장하고 읽어오게 된다. (기본값 false)
:unless_exist write 메소드에서 사용되는 옵션으로 :unless_exist가 true인 경우, 값이 존재하지 않는 경우에만 값을 저장하게 된다. 기본적으로는 값이 존재하는 경우, 기존값을 대체한다. (기본값 false)
:expires_in write 메소드에서 사용되는 옵션으로 cache가 유효한 시간을 초 단위로 설정한다. cache가 일정 시간에 한번씩 업데이트되어야 하는 경우에 이 옵션을 사용할 수 있다.
  1. cache.write('inocrazy', 'Crazy For Innovation!', :raw => true)
  2. # :unless_exist가 true로 설정되었고, 이미 값이 존재하므로 저장되지 않는다.
    cache.write('inocrazy', 'InoCrazy', :unless_exist => true, :expires_in => 10.miutes)
    cache.read('inocrazy', :raw => true)
    => 'Crazy For Innovation!


Rails에서 Cache

지금까지 ActiveSupport::Cache에 대해서 자세히 살펴보았다. 이제 Rails에서 실제로 caching store를 설정하고, 사용하는 방법에 대해서 살펴보자. 특정 caching store를 설정하기 위해서는 config/environment.rb (또는 config/environments 디렉토리의 환경별 설정파일)에서 다음과 같이 설정할 수 있다.


  1. # FileStore 사용. '/tmp/cache'를 cache 저장소로 설정.
    config.cache_store = :file_store, '/tmp/cache'
    # MemoryStore 사용
    config.cache_store = :memory_store
    # DRbStore 사용, 192.168.10.1:9192의 drb server로 설정.
    config.cache_store = :drb_store, 'druby::/192.168.10.1:9192'
    # MemCacheStore 사용. 192.168.10.1:11211, 192.168.10.2:11212를 memcache server로 설정
    config.cache_store = :mem_cache_server, '192.168.10.1:11211', '192.168.10.2:11212', :namespace => 'inocrazy'
    # CompressedMemCacheStore 사용
    config.cache_store = :compressed_mem_cache_store, 'localhost'

위에서 언급하였듯이, 위의 설정은 내부적으로 ActiveSupport::Cache.lookup_store 메소드를 통해서 cache 인스턴스를 설정하게 된다. 위의 설정이 존재하지 않는 경우의 기본 caching store는 FileStoreMemoryStore 중 하나를 사용하게 된다. tmp/cache 디렉토리가 존재할 경우, FileStore가 사용되며, 그렇지 않을 경우 MemoryStore가 기본이 된다. Rails에서는 기본적으로 global cache를 생성한다. 실제 코드에서 이를 사용하기 위해서는 RAILS_CACHE 전역변수나 Rails.cache를 통해서 접근할 수 있다.


  1. # 'date'라는 key를 갖는 cache에 쓰고 읽는다.
    Rails.cache.write('date', Date.today)
    Rails.cache.read('date')
    => '2008-07-02'

    # 'time'이라는 cache가 존재하지 않으므로 block의 실행결과를 cache에 저장하고, 리턴한다.
    Rails.cache.fetch('time') { Time.now }
    => Wed Jul 02 02:44:34 +0900 2008
    # 이미 'time'이라는 cache가 존재하므로 cache에서 값을 읽어온다.
    Rails.cache.fetch('time') { Time.now }
    => Wed Jul 02 02:44:34 +0900 2008


정리

Rails 2.1에서는 기존에 복잡한 설정과 추가적인 gem/plugin으로 구현해야 했던, cache 처리를 ActiveSupport::Cache를 통해서 간편하게 사용할 수 있게 되었다. 이 cache를 적절히 사용함으로써 Rails 서비스의 Performance를 더욱 향상시켜보자. ^^


참조




이 글은 스프링노트에서 작성되었습니다.

2008/07/02 04:23 2008/07/02 04:23

Rails 2.1 : Dirty Objects

[Development]

원문(http://inocrazy.com/docs/7)에서 좀 더 깔끔하게 보실 수 있습니다.

속성의 변화를 추적하기 - ActiveRecord::Dirty

다음과 같은 경우를 생각해보자. Book이라는 모델이 있고, Book은 category를 나타내는 category_id라는 컬럼을 가지고 있다. Book의 category가 변경될 때마다 (즉, category_id 값이 변할 때마다) 특정 counter 테이블을 변경시켜줘야 한다면 어떻게 구현할 수 있을까? Book이 update되는 경우에 category_id가 변경되었는지 여부를 확인해서 counter 테이블을 갱신해야 할 것이다. 막상 구현하려고 하면, Book의 before_update callback을 이용해야하는 것은 바로 감이 오지만, category_id의 변경여부를 모니터링하는 방법은 바로 해결책을 내놓기가 어렵다.


즉, 위의 예처럼 모델의 특정 속성의 변경 여부를 모니터링할 필요가 있을 때, 쉽게 사용할 수 있는 방법이 Changeset 9127에서 추가되었다. 물론 기존에도 동일한 기능을 하는 acts_as_modified 라는 플러그인이 존재하였으나, Rails에 기능으로서 포함됨으로써 보다 편하게 사용할 수 있게 되었다. ActiveRecord::Dirty 모듈은 ActiveRecord::Base 클래스에 mix-in 되면서, '_changed?', '_change', '_will_change!', '_was' 접미사를 갖는 suffixed attribute method(접미사가 붙은 속성메소드)를 추가한다. suffixed attribute method는 ActiveRecord::AttributeMethodsattribute_method_suffix 클래스 메소드에 의해서 쉽게 추가할 수 있는데, 추후 다른 문서에서 ActiveRecord::AttributeMethods에 대해서 구체적으로 살펴볼 것이다.


ActiveRecord::Dirty에 의해 추가되는 메소드는 다음과 같다.

  • obj.<attr>_changed?
  • obj.<attr>_was
  • obj.<attr>_change
  • obj.<attr>_will_change!
  • obj.changed?
  • obj.changed
  • obj.changes

사용법 파악하기

위에서 열거한 메소드들을 하나씩 살펴보면서 사용법을 파악해보자. Person이라는 모델이 name이라는 속성을 갖는다고 가정하자. (이 단락의 소스코드들은 하나의 코드를 편의상 나누어둔 것이다.)


  1. person = Person.find_by_name('Dongkyu Kim')
  2. person.name          # => 'Dongkyu Kim'
  3. person.name_changed? # => false

'Dongkyu Kim'이라는 name 속성을 갖는 레코드를 가져온다. <attr>_changed? 메소드는 해당 속성의 변경 여부를 알려준다. 단, 이 변경 여부는 저장되기 전에만 확인할 수 있다. 저장이 되면서, 내부에서 변경정보를 유지하고 있는 @changed_attributes 속성이 리셋되기 때문이다.


  1. person.name = 'Kim Dongkyu'
  2. person.name_changed? # => true
  3. person.name_was      # => 'Dongkyu Kim'
  4. person.name_change   # => ['Dongkyu Kim', 'Kim Dongkyu']

name이 변경되었기 때문에 name_changed?는 true를 리턴한다. <attr>_was 메소드는 변경 이전의 값을 알려준다. 또한 <attr>_change 메소드를 통해서 변경 이전 값과 이후의 값을 Array로 받을 수 있다.


  1. person.changed?  # => true
  2. person.changed   # => ['name']
  3. person.changes   # => { 'name' => ['Donkyu Kim', 'Kim Dongkyu'] }

obj.changed? 메소드는 하나의 속성이라도 변경되었을 경우, true를 리턴한다. obj.changed 메소드는 변경된 속성명을 Array로 알려준다. 또한 obj.changes 메소드는 변경된 속성명과 함께 해당 속성의 변경 이력을 Hash 값으로 전달해준다.


  1. person.save
  2. person.changed?      # => false
  3. person.name_changed? # => false

위에서 언급하였듯이 일단 저장하게 되면, 저장 이전의 변경 정보는 알 수 없게 된다.


몇 가지 주의사항들

위에서 설명한 메소드들은 전혀 어려울 것 없이 코드에서 사용할 수 있다. 이 단락에서는 ActiveRecord::Dirty의 메소드를 사용하는데 있어서 주의해야할 몇 가지를 언급하면서 문서를 마치고자 한다.


<attr>= writer로 속성을 변경하지 않는 경우

ActiveRecord::Dirty의 메소드들은 기본적으로 <attr>= writer로 값을 변경하는 경우에, 변경 정보를 모니터링할 수 있다. 따라서 다른 메소드로 속성 값을 변경하는 경우에는, <attr>_will_change! 메소드로 해당 속성이 변경될 것임을 미리 알려주어야만 속성의 변경 여부를 파악할 수 있다.


  1. person = Person.find_by_name('Dongkyu Kim')
  2. person.name_will_change!  # => name 속성이 다른 메소드로 변경될 것임을 알림.
  3. person.name.upcase!       # => <attr>= writer로 변경하지 않음.
  4. person.name_changed?      # => true

같은 값으로 변경하는 경우에는?

만약 속성의 값을 같은 값으로 설정하는 경우, 또는 A에서 B로 변경했다가 다시 A로 변경하는 경우의 changed?의 결과는 어떻게 될까?


  1. person = Person.find_by_name('Dongkyu Kim')
  2. person.name                     # => 'Dongkyu Kim'
  3. person.name_changed?            # => false
  4. person.name = 'Dongkyu Kim'     # 같은 값으로 설정한다.
  5. person.name_changed?            # => false
  6. person.name = 'Kim Dongkyu'
  7. person.name_changed?            # => true
  8. person.name_change              # => ['Dongkyu Kim', 'Kim Dongkyu']
  9. person.name = 'Dongkyu Kim'
  10. person.name_changed?            # => true
  11. person.name_change              # => ['Dongkyu Kim', 'Dongkyu Kim']
  12. person.changed?                 # => true

위의 예제에서 보는 것과 같이 같은 값으로 변경하는 경우에는 변경된 것으로 인식하지 않는다. 하지만 한번이라도 다른 값으로 변경된 속성은 changed?를 true로 리턴하게 된다.


참조

이 글은 스프링노트에서 작성되었습니다.

2008/04/16 03:47 2008/04/16 03:47

Rails 2.1 : Gem Dependencies

[Development]

원문(http://inocrazy.com/docs/4)에서 좀 더 깔끔하게 보실 수 있습니다.

Rails와 Gem

Rails를 개발하다보면 외부의 Gem에 의존하게 되는 경우가 있다. 예를 들어 RSS를 읽어와서 item의 title과 link를 추출하는 경우에, 빠르고 간편한 처리를 위해 hpricot을 사용할 수 있을 것이다. 또한 업로드하는 파일의 thumbnail을 생성하기 위해서 rmagick gem을 필요로 하게된다. 이 경우 Rails Application은 hpricotrmagick이라는 gem에 의존적이게 된다. 따라서 해당 gem이 설치되어 있지 않거나, 필요로 하는 버전 이하의 gem이 설치되어 있을 경우, 정상적인 결과를 보장할 수 없게 된다. 기존의 Rails에서는 이러한 Gem 의존성 문제를 프로그램적으로 해결할 수 있는 방법이 없었다. 그래서 Rails 2.1에서 Gem 의존성을 정의하고, 그에 따라서 Gem을 자동으로 로드해주는 기능이 추가되게 되었다.


다음 코드는 Rails 2.1에서의 config/environments.rb 파일 중, 초기화와 관련된 부분이다.

  1. Rails::Initializer.run do |config|
      config.gems "bj"
      config.gems "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
      config.gems "aws-s3", :lib => "aws/s3"
    end

위와 같이 초기화 블럭에서 config.gems GEMNAME <options> 형식으로 Gem 의존성을 정의할 수 있다. 위의 코드를 통해서 이 Rails Application은 "bj", "hpricot", "aws-s3" 이라는 gem들에 의존하고 있다는 것을 알 수 있다. #gems는 Rails::Configuration 클래스에 새로 추가된 메소드로서 주어진 옵션으로 Rails::GemDependency 클래스의 인스턴스를 생성해주는 메소드이다. 위와 같이 의존성이 정의된 gem은 Rails Application이 가동될 때, 해당 gem의 존재 여부와 버전의 적합성을 판단하여 gem을 로드할 수 없을 경우, 에러 메시지를 발생시킨게 된다.


Rails::GemDependency

다음은 Rails::GemDependeny의 initialize 메소드다. 아래의 코드에서 Gem 의존성을 설정할 때 설정할 수 있는 옵션의 종류를 알 수 있다.

  1. def initialize(name, options = {})
      @name     = name.to_s
      if options[:version]
       @requirement = Gem::Requirement.create(options[:version])
       @version     = @requirement.instance_variable_get("@requirements").first.last
      end
      @lib      = options[:lib]
      @source   = options[:source]
      @loaded   = false
      @load_paths_added = false
      @unpack_directory = nil
    end

  1. :version

    우선 version 정보를 설정할 수 있다. Ruby 코드에서 특정 버전의 gem을 필요로 하는 경우, 다음과 같이 표기하였다. 위 코드에서 '~>3.0' 부분이 gem에 대한 버전 정보로서, GemDependency에서도 동일한 표기법으로 버전 정보를 설정한다.

    1. gem 'RedCloth', '~> 3.0'   # gem을 $LOAD_PATH에 추가.
    2. require 'RedCloth'

    version 정보로 Gem::Requirement create 메소드(factory method)인스턴스를생성한후에, 인스턴수변수에서 Gem::Version 정보를추출한다.



  2. :lib

    gem 이름과 require로 불러오는 이름이 다를 경우, :lib으로 라이브러리명을 명시할 수 있다.

    1. gem 'aws-s3', '>= 0.4.0'
      # require 'aws/s3'
      config.gem 'aws-s3', :lib => 'aws/s3', :version => '>= 0.4.0'

  3. :source

    gem을 특정 repository에서 install해야하는 경우, :source로 명시할 수 있다. 명시한 source 정보는 gems:install rake task에서 사용되게 된다.

    1. config.gems "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"

Gems Rake Task

정의된 gem 의존성을 통해서, 설치되지 않은 gem을 확인하고, 설치할 수 있는 Rake Task도 추가되었다. 특히 신규 서버에 Rails Application을 설치하는 경우(ex. App. server 추가), 기존에는 Capistrano 등의 배포툴에서 Gem 의존성을 보장하는 코드를 작성해서 일괄적으로 gem을 설치하곤 했다. 하지만 gems rake task를 통해서 보다 간편하고 정확하게 Gem 의존성을 보장할 수 있게 되었다. 아래의 이미지에서 rake -T 명령어로 gems rake task가 추가된 것을 볼 수 있다.


rake_gems(2).png


  1. rake gems

    Rails에서 의존하고있는 gem의 목록을 보여준다. 아래의 이미지에서 Rails Application이 hpricotspringnote_resources gem에 의존하고 있다는 것을 볼 수 있다. 만약 의존하고 있는 gem을 발견하지 못 할 경우, gem 이름 앞의 체크표시([*])가 표시되지 않으며, 에러 메시지를 보여준다.

    rake_gems(1).png


  2. rake gems:install

    필요로 하는 모든 gem을 설치한다. 만약 source 정보를 명시하였다면 해당 source로 부터 gem을 설치한다.


  3. rake gems:unpack <GEM=[GEMNAME]>

    vendor/gems 디렉토리에 gem을 unpack한다. 특정 Gem의 source 코드가 궁금한 경우, gem repository에 직접 접근해서 소스코드를 보지 않고, 현재 디렉토리에 unpack해서 확인하는 경우가 많다.

    1. gem unpack GEMNAME

    그와 같이 repository에 있는 gem을 수정해서 자신만의 버전으로 사용하거나 하는 경우, unpack을 통해서 따로 설치한 gem을 사용할 수 있다. 이 경우 우선순위는 vendor/gems 에 설치된 gem이 갖게된다.


    Changeset 9140까지는 GEM=[GEMNAME]을 명시하여, 특정 Gem만 unpack할 수 있었으나, Changeset 9215부터 gem 이름을 명시하지 않을 경우, 모든 gem을 unpack하도록 기능 추가되었다.


  4. rake gems:build <GEM=[GEMNAME]>

    Chageset 9215에서 추가된 task로서 unpack된 gem(들)을 빌드한다. (native extension)


참조

이 글은 스프링노트에서 작성되었습니다.

2008/04/04 21:36 2008/04/04 21:36