私はRails 3.1エンジンをPostsという名前空間で作成しました。したがって、コントローラーはapp/controllers/posts /にあり、モデルはapp/models/postsにあります。モデルは問題ありません。1つのモデルの仕様は次のようになります...
module Posts
describe Post do
describe 'Associations' do
it ...
end
...そしてすべてが正常に動作します。
ただし、コントローラーの仕様は機能しません。 Railsエンジンは/ postsにマウントされていますが、コントローラーはPosts :: PostControllerです。したがって、テストでは、コントローラールートがposts/postsであるかどうかを探します。
describe "GET index" do
it "assigns all posts as @posts" do
Posts::Post.stub(:all) { [mock_post] }
get :index
assigns(:posts).should eq([mock_post])
end
end
これは...
1) Posts::PostsController GET index assigns all posts as @posts
Failure/Error: get :index
ActionController::RoutingError:
No route matches {:controller=>"posts/posts"}
# ./spec/controllers/posts/posts_controller_spec.rb:16
テストアプリのroutesファイルであらゆる種類のトリックを試しました...:namespaceなど、役に立ちませんでした。
これを機能させるにはどうすればよいですか?エンジンはコントローラーを/ postsに配置するので、そうではないようですが、名前空間はテストの目的でコントローラーを/ posts/postsに配置します。
enginex によって生成されるようなダミーのRailsアプリを使用して、エンジンをテストしていると想定しています。
エンジンはダミーアプリにマウントする必要があります。
spec/dummy/config/routes.rb
:
Dummy::Application.routes.draw do
mount Posts::Engine => '/posts-prefix'
end
私の2番目の仮定は、エンジンが分離されていることです。
lib/posts.rb
:
module Posts
class Engine < Rails::Engine
isolate_namespace Posts
end
end
これらの2つの仮定が本当に必要かどうかはわかりませんが、それが私自身のエンジンの構造です。
これの代わりに、回避策は非常に簡単です
get :show, :id => 1
これを使って
get :show, {:id => 1, :use_route => :posts}
:posts
記号は、エンジンの名前であり、マウントされているパスではありません。
これが機能するのは、getメソッドのパラメーターがActionDispatch::Routing::RouteSet::Generator#initialize
(定義済み ここ )に直接渡され、@named_route
を使用してRack::Mount::RouteSet#generate
から正しいルートを取得するためです(を参照)。 ここ および ここ )。
Rails内部に飛び込むのは楽しいですが、かなり時間がかかるので、毎日これを行うことはありません;-)。
HTH
この問題を回避するには、提供されているget
、post
、put
、およびdelete
メソッドをオーバーライドして、常に_use_route
_をパラメータとして。
私はこれの基礎としてブノワの答えを使用しました。ありがとう!
_module ControllerHacks
def get(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "GET")
end
# Executes a request simulating POST HTTP method and set/volley the response
def post(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "POST")
end
# Executes a request simulating PUT HTTP method and set/volley the response
def put(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "PUT")
end
# Executes a request simulating DELETE HTTP method and set/volley the response
def delete(action, parameters = nil, session = nil, flash = nil)
process_action(action, parameters, session, flash, "DELETE")
end
private
def process_action(action, parameters = nil, session = nil, flash = nil, method = "GET")
parameters ||= {}
process(action, parameters.merge!(:use_route => :my_engine), session, flash, method)
end
end
RSpec.configure do |c|
c.include ControllerHacks, :type => :controller
end
_
Rspec-Rails routes
ディレクティブを使用します。
describe MyEngine::WidgetsController do
routes { MyEngine::Engine.routes }
# Specs can use the engine's routes & named URL helpers
# without any other special code.
end
this の回答に基づいて、次の解決策を選択しました。
_#spec/spec_helper.rb
RSpec.configure do |config|
# other code
config.before(:each) { @routes = UserManager::Engine.routes }
end
_
追加の利点は、すべてのコントローラー仕様にbefore(:each)
ブロックを含める必要がないことです。
isolate_namespace
がない、または使用できない場合の問題の解決策:
module Posts
class Engine < Rails::Engine
end
end
コントローラの仕様では、ルートを修正するには:
get :show, {:id => 1, :use_route => :posts_engine}
isolate_namespace
を使用しない場合、Railsはアプリルートに_engineを追加します。
実行中のアプリケーションにAPIを提供するgemを会社向けに開発しています。 Rails 3.0.9を使用していますが、最新のRspec-Rails(2.10.1)を使用しています。Railsエンジンの宝石。
match '/companyname/api_name' => 'CompanyName/ApiName/ControllerName#apimethod'
次のようなエラーが発生していました
ActionController::RoutingError:
No route matches {:controller=>"company_name/api_name/controller_name", :action=>"apimethod"}
RSpecがそれに一致するように、アンダースコアの場合にルートを再定義する必要があることがわかりました。
match '/companyname/api_name' => 'company_name/api_name/controller_name#apimethod'
Rspecコントローラーのテストでは、アンダースコアの場合に基づく逆ルックアップが使用されていると思いますが、キャメルケースまたはアンダースコアの場合でルートを定義すると、Railsがルートをセットアップして解釈します。