[英]Testing an association model helper method rails rspec
I have two models, User
and Account
. 我有两个模型,
User
和Account
。
# account.rb
belongs_to :user
# user.rb
has_one :account
Account
has an attribute name
. Account
具有属性name
。 And in my views, I was calling current_user.account.name
multiple times, and I heard that's not the great of a way to do it. 在我看来,我已经多次调用
current_user.account.name
,并且听说这不是一种很好的方法。 So I was incredibly swift, and I created the following method in my user.rb
所以我非常快,我在
user.rb
创建了以下方法
def account_name
self.account.name
end
So now in my view, I can simply call current_user.account_name
, and if the association changes, I only update it in one place. 因此,现在在我看来,我可以简单地调用
current_user.account_name
,并且如果关联发生更改,我只会在一个地方进行更新。 BUT my question is, do I test this method? 但是我的问题是,我可以测试这种方法吗? If I do, how do I test it without any mystery guests?
如果可以,如何在没有任何神秘客人的情况下进行测试?
I agree there is nothing wrong with current_user.account.name - while Sandi Metz would tell us "User knows too much about Account" this is kind of the thing you can't really avoid w/ Active Record. 我同意current_user.account.name没什么问题-尽管Sandi Metz会告诉我们“用户对帐户了解太多”,这是您无法避免使用Active Record的事情。
If you found you were doing a lot of these methods all over the User model you could use the rails delegate method: 如果发现您在整个User模型中都使用了许多这些方法,则可以使用rails委托方法:
delegate :name, :to => :account, :prefix => true
using the :prefix => true option will prefix the method in the User model so it is account_name. 使用:prefix => true选项将在用户模型中将该方法添加为account_name。 In this case I would assume you could write a very simple unit test on the method that it returns something just incase the attribute in account would ever change your test would fail so you would know you need to update the delegate method.
在这种情况下,我假设您可以在方法上编写一个非常简单的单元测试,以使其返回某些信息,以防万一帐户中的属性会更改您的测试失败,因此您将需要更新委托方法。
Personally I see no good reason for any of this. 我个人认为没有任何理由要这样做。 Just use current_user.account.name.
只需使用current_user.account.name。
If you are worrying about efficiency, have current_user return a user that joins account. 如果您担心效率,请让current_user返回一个加入帐户的用户。
This is going to be a bit off-topic. 这将有点题外话。 So, apologies in advance if it's not interesting or helpful.
因此,如果没有意思或没有帮助,请提前道歉。
TL;DR: Don't put knowledge of your models in your views. TL; DR:不要在您的视图中放入模型知识。 Keep your controllers skinny.
使您的控制器保持瘦身。 Here's how I've been doing it.
这就是我一直在做的事情。
In my current project, I've been working to make sure my views have absolutely no knowledge of anything about the rest of the system (to reduce coupling). 在我当前的项目中,我一直在努力确保我的视图对系统其余部分完全一无所知(以减少耦合)。 This way, if you decide to change how you implement something (say,
current_user.account.name
versus current_user.account_name
), then you don't have to go into your views and make changes. 这样,如果您决定更改实现方式(例如
current_user.account.name
与current_user.account_name
),则无需进入视图并进行更改。
Every controller action provides a @results
hash that contains everything the view needs to render correctly. 每个控制器操作都提供一个
@results
哈希,其中包含视图需要正确呈现的所有内容。 The structure of the @results
hash is essentially a contract between the view and the controller. @results
哈希的结构本质上是视图和控制器之间的协定。
So, in my controller, @results
might look something like {current_user: {account: {name: 'foo'}}}
. 因此,在我的控制器中,
@results
可能类似于{current_user: {account: {name: 'foo'}}}
。 And in my view, I'd do something like @results[:current_user][:account][:name]
. 在我看来,我会做类似
@results[:current_user][:account][:name]
。 I like using a HashWithIndifferentAccess
so I could also do @results['current_user']['account']['name']
and not have things blow up or misbehave. 我喜欢使用
HashWithIndifferentAccess
所以我也可以执行@results['current_user']['account']['name']
且不会发生异常或行为异常。
Also, I've been moving as much logic as I can out of controllers into service objects (I call them 'managers'). 另外,我一直在将尽可能多的逻辑从控制器移到服务对象(我称它们为“管理器”)中。 I find my managers (which are POROs) a lot easier to test than controllers.
我发现我的经理(即PORO)比控制器要容易得多。 So, I might have:
因此,我可能有:
# app/controllers/some_controller.rb
class SomeController
def create
@results = SomeManager.create(params)
if @results[:success]
# happy routing
else
# sad routing
end
end
end
Now, my controllers are super skinny and contain no logic other than routing. 现在,我的控制器非常苗条,除了路由之外不包含任何逻辑。 They don't know anything about my models.
他们对我的模型一无所知。 (In fact, almost all of my controller actions look exactly the same with essentially the same six lines of code.) Again, I like this because it creates separation.
(实际上,几乎所有的控制器动作在基本上相同的六行代码中看起来都完全相同。)同样,我喜欢这样做是因为它会产生分离。
Naturally, I need the manager: 当然,我需要经理:
#app/managers/some_manager.rb
class SomeManager
class << self
def create(params)
# do stuff that ends up creating the @results hash
# if things went well, the return will include success: true
# if things did not go well, the return will not include a :success key
end
end
end
So, in truth, the structure of @results
is a contract between the view and the manager, not between the view and the controller. 因此,实际上,
@results
的结构是视图和管理器之间的契约,而不是视图和控制器之间的契约。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.