[英]Ruby on rails, Rubocop refactoring
Offenses:罪行:
app/controllers/tasks_controller.rb:12:3: C: Metrics/AbcSize: Assignment Branch Condition size for create is too high. app/controllers/tasks_controller.rb:12:3: C: Metrics/AbcSize: 用于创建的分配分支条件大小太高。 [<3, 19, 1> 19.26/17] def create... [<3, 19, 1> 19.26/17] 定义创建...
app/controllers/tasks_controller.rb:24:3: C: Metrics/AbcSize: Assignment Branch Condition size for update is too high. app/controllers/tasks_controller.rb:24:3: C: Metrics/AbcSize: 更新的分配分支条件大小太高。 [<4, 20, 1> 20.42/17] def update... [<4, 20, 1> 20.42/17] 定义更新...
27 files inspected, 2 offenses detected检查了 27 个文件,发现了 2 个违规行为
def create
@task = current_user.projects.find(params[:project_id]).tasks.new
@task.title = task_params[:title]
@task.save ? (redirect_to root_url) : (flash[:error] = @task.errors.full_messages) | (render
:new)
end
def update
@task = current_user.tasks.find(params[:id])
@task.title = task_params[:title]
@task.deadline = task_params[:deadline]
@task.save ? (redirect_to root_url) : (flash[:error] = @task.errors.full_messages) | (render
:edit)
end
How can i refactor it to resolve rubocop's offences?我如何重构它以解决 rubocop 的罪行?
Solved problem by creating private methods:通过创建私有方法解决了问题:
def create
tasknew
tasktitle
@task.save ? (redirect_to root_url) : (flash[:error] = @task.errors.full_messages) | (render :new)
end
def update
taskfind
tasktitle
@task.deadline = task_params[:deadline]
@task.save ? (redirect_to root_url) : (flash[:error] = @task.errors.full_messages) | (render :edit)
end
private
def tasktitle
@task.title = task_params[:title]
end
def taskfind
@task = current_user.tasks.find(params[:id])
end
def tasknew
@task = current_user.projects.find(params[:project_id]).tasks.new
end
You've extracted the simplest part of your code and left the most complex.您已经提取了代码中最简单的部分并留下了最复杂的部分。 The point of the ABC metric is to point out complex parts of your code so you can simplify them, and possibly catch bugs. ABC 指标的重点是指出代码的复杂部分,以便您可以简化它们,并可能发现错误。 If you just extract the most trivial parts to satisfy the cop, you might as well disable it.如果你只是提取最琐碎的部分来满足警察,你还不如禁用它。
@task.save? (redirect_to root_url): (flash[:error] = @task.errors.full_messages) | (render:edit)
@task.save? (redirect_to root_url): (flash[:error] = @task.errors.full_messages) | (render:edit)
is obviously the most complex part of those methods. @task.save? (redirect_to root_url): (flash[:error] = @task.errors.full_messages) | (render:edit)
显然是这些方法中最复杂的部分。 I'm having trouble understanding it.我很难理解它。 Why is there a bitwise or?为什么有按位或? And it's duplicated, except or what to render.它是重复的,除了要渲染的内容。
Let's pull this apart.让我们把它分开。 First, turn the ternary operator into an if/else.首先,将三元运算符转换为 if/else。
if @task.save
redirect_to root_url
else
(flash[:error] = @task.errors.full_messages) | (render :edit)
end
I don't think that |
我不这么认为|
is actually doing anything.实际上是在做任何事情。 It's just a way to cram two statements into one.这只是一种将两个语句塞进一个语句的方法。
if @task.save
redirect_to root_url
else
flash[:error] = @task.errors.full_messages
render :edit
end
That is much easier to understand, and it reduces the ABC a bit.这更容易理解,并且稍微减少了 ABC。
Next is to put the find code into their own private methods.接下来是将查找代码放入自己的私有方法中。 Just a simple extract method.只是一个简单的提取方法。
# Note I left it at just finding the associated project.
# I left the .tasks.new off because that's very specific.
private def current_project
current_user.projects.find(params[:project_id])
end
private def current_task
current_user.tasks.find(params[:id])
end
def create
@task = current_project.tasks.new
@task.title = task_params[:title]
if @task.save
redirect_to root_url
else
flash[:error] = @task.errors.full_messages
render :edit
end
end
def update
@task = current_task
@task.title = task_params[:title]
@task.deadline = task_params[:deadline]
if @task.save
redirect_to root_url
else
flash[:error] = @task.errors.full_messages
render :edit
end
end
And that will do it.这样就可以了。 You could take this a step further and extract the save logic, passing in where to render and any other details that might change.您可以更进一步,提取保存逻辑,传入渲染位置和任何其他可能更改的细节。
# Note the use of defaults.
private def save_task(render:, redirect_to: root_url)
if @task.save
redirect_to(redirect_to)
else
flash[:error] = @task.errors.full_messages
render(render)
end
end
def create
@task = current_project.tasks.new
@task.title = task_params[:title]
save_task(render: :new)
end
def update
@task = current_task
@task.title = task_params[:title]
@task.deadline = task_params[:deadline]
save_task(render: :edit)
end
It reveals some possible issues.它揭示了一些可能的问题。
create
and update
are using different methods of finding the task. create
和update
使用不同的方法来查找任务。 Seems fishy.好像很腥Your tasknew
and taskfind
hide this difference making the code harder to understand.您的tasknew
和taskfind
隐藏了这种差异,使代码更难理解。
And update
is setting the deadline, but create
is not. update
是设置最后期限,但create
不是。 That suggests setting the @task attributes from task_params should be extracted into a single method.这表明从 task_params 设置 @task 属性应该提取到一个方法中。
Note that I avoided putting the assignment into the private methods.请注意,我避免将分配放入私有方法中。 Even though this technically reduces ABC, it makes the code harder to understand because the method call has a side effect ;尽管这在技术上减少了 ABC,但它使代码更难理解,因为方法调用有副作用; it changes the state of the object.它改变了 object 的 state。 Side effects have to be done with purpose.副作用必须有目的地进行。
For example, one could turn current_task
and current_project
into memoized accessors with defaults.例如,可以将current_task
和current_project
转换为具有默认值的记忆访问器。
private def current_project
@current_project ||= current_user.projects.find(params[:project_id])
end
Now it will only load the object once.现在它只会加载 object 一次。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.