Rails - 在另一个视图中的部分无法访问其控制器

时间:2015-07-18 02:16:04

标签: ruby-on-rails

我正在尝试构建一个配置文件页面,该页面显示仅发送给所请求用户的帖子,并允许访问者编写自己的帖子。因为这个简化的示例应该有两个不同的控制器:用户和帖子,我为每个帖子操作制作了部分内容,以便在用户的show动作中呈现。

我的views目录的目录结构如下所示:

- posts
  - _index.html.erb
  - _new.html.erb

- users
  - show.html.erb
  ... (etc.)

在用户show.html.erb中显示这些部分内容的部分:

<section>
    <h3>Posts:</h3>
    <%= render '/posts/new', :post => Post.new %>
    <%= render '/posts/index', :posts => Post.where(target_id: params[:id]) %>
</section>

我最终发现您可以将变量传递到此render行中的部分变量,虽然这有效,但它非常混乱,可能并不遵循最佳做法。

理想情况下,我希望将这些部分与帖子控制器连接起来,这样我就可以在一个不是视图的地方编写更复杂的数据库查询:

class PostsController < ApplicationController
def new
    @post = Post.new
end

def index
    @posts = Post.where(target_id: params[:id])
end

def create
    @post = Post.new(post_params)   
    @post.user_id = current_user.id
    @post.target_id = params[:post][:target_id]

    if @post.save
        redirect_to :back, notice: 'You published a post!'
    else
        render new
    end
end

private
    def post_params
        params.require(:post).permit(:body)
    end
end

目前,我还没有找到办法。我知道这是一个新问题,但感谢您提前提供任何帮助。

2 个答案:

答案 0 :(得分:2)

您正在尝试将控制器视为模型:在后控制器中进行后期工作,用户在用户控制器中工作。但控制器是面向任务的,而不是面向模型的。

由于您希望在用户表单中添加帖子信息,因此将其收集到用户控制器中是很典型的。 E.g。

class UsersController < ApplicationController
  def show
    ...
    @posts = Post.where(user_id: user.id)
  end
end

在展示模板中显示@posts个实例变量以及它调用的任何部分变量。但是许多程序员更喜欢通过render参数明确地发送它,因为它更具功能性:

<%= render '/posts/post_list', posts: @posts %>

一方面,当您可以一目了然地看到所有部分依赖项时,它更容易重构。

答案 1 :(得分:0)

我同意@ Mori的建议。正如他所说,你试图在控制器中加入太多逻辑。我认为这是您试图将其从视图中删除的结果,这是正确的想法,但您希望业务逻辑在模型中。

此外,index的{​​{1}}和new操作永远不会被调用。例如,在调用渲染PostsController时,即呈现视图,而不是控制器操作。因此,那些控制器动作没有理由存在。

我可能会以与Mori描述的方式不同的方式实现修复。建议的做法是尝试将尽可能少的实例变量从控制器传递到视图(see 3rd bullet in the linked section)。

由于它确实是我们在这里讨论的posts/new的{​​{1}}动作,我作为有人试图理解你的代码会假设你传递给{{的实例变量1}}视图类似于show

在实例化UsersController对象时,您可能希望使用show方法。 @user语句允许您使用尽可能少的查询来加载实例化所需的其他模型(防止N + 1查询情况)。如果有数千个匹配的帖子,你可能不想加载每一个帖子,所以我对其进行了任意限制。

<强> UsersController

includes

查看

@user

如果要渲染编辑操作(includes知道要使用哪个操作,则将部分替换为新def show @user = User.find(params[:id]).includes(:received_posts).limit(10) end #.... 作为名为<section> <h3>Posts:</h3> <% unless @user.id == current_user.id %> <%= render 'posts/form', post: Post.new(user_id: @user.id) %> <% end %> <%= render @user.received_posts %> </section> 的视图将允许您重复使用该表单通过调用传递的模型post方法提交。

请注意,此代码假定posts/form模型与设置为form_for的帖子具有第二关系,但您可以将其更改为反映现实的内容。通过将persisted?集合传递给render方法,Rails非常聪明,知道如果要呈现User模型的集合以查找received_posts部分并为每个部署渲染一个received_posts。看起来IMO看起来更干净一点。只需确保将Post代码移到其中即可。 posts/_post暗示这是它自己的行为,而不是用作其他东西的部分行为。