使用嵌套资源在会话中存储参数

时间:2015-07-16 01:57:17

标签: ruby-on-rails forms ruby-on-rails-4 parameters controller

我正在使用Rails 4。

我有子文章嵌入文章。当用户需要在提交之前创建帐户时,我会在会话中存储子文章中的所有表单数据。

以下是我正在使用的内容(subarticles_controller):

def create
  if current_user.nil?

  session[:subarticle] = params

  redirect_to new_user_session_path
end 

然后在用户注册后,使用

创建包含存储的参数的子文章
if session[:subarticle].present?
  @subarticle = current_user.subarticles.create(session[:subarticle]["subarticle"])

  session[:subarticle] = nil

  flash[:notice] = "Awesome, you are logged in and your answer is undergoing review."      

  edit_user_registration_path
end

但是,我遇到了麻烦,保存了创建子文章的article_id。有人能指出我正确的方向吗?

1 个答案:

答案 0 :(得分:2)

更好的方法是将访客用户创建的(子)文章保存在数据库中。

class SubArticlesController < ApplicationController 

  before_action :set_article, only: [:show, :edit, :update, :destroy]

  # ...

  def create
    @subarticle = Article.new(article_params) do |a|
      if current_user
        a.user = current_user
      else
        a.token = SecureRandom.hex
      end
    end
    if @subarticle.save
      if @subarticle.user
        redirect_to @subarticle
      else
        session[:after_sign_in_path] = edit_article_path(@subarticle, token: @subarticle.token)
        redirect_to new_user_session_path, notice: 'Please sign in to finalize your article.'
      end
    else
      render :new
    end
  end

  def edit
    if @subarticle.user.nil? && @subarticle.token != params[:token]
      redirect_to root_path, alert: 'You are not authorized.'
    end

    flash[:notice] = 'Please press save again to publish your post.' unless @subarticle.user
    render :edit
  end

  def update 
    # The @subarticle.token should be included in the edit form 
    unless @subarticle.user && @subarticle.token == params[:sub_article][:token]
      # let the current user claim the article
      @subarticle.user = current_user
    end

    if @subarticle.update(article_params)
      redirect_to @subarticle
    else
      render :edit
    end
  end

  private

  def set_article
    @subarticle = Article.find(params[:id])
  end

  def sub_article_params
    params.require(:sub_article).permit(...)
  end
end

因此,我们在此向用户提供指向文章编辑页面的链接,他/她可以在登录后“完成”文章。

由于恶意用户可能通过猜测ID并输入编辑网址来“窃取”无人认领的文章,我们会添加一个随机令牌,我们将其与文章一起存储在数据库中并添加到网址中。不是100%万无一失,但至少更好。

要完成这项工作,您还需要在表单中添加一个令牌字段:

<%= form_for(@subarticle) do |f| %>
  ...
  <%= f.hidden_field :token %>
  ...
<% end %>

您可能想要考虑这个问题的原因是因为会话存储通常是基于内存的,如果您有大量的流量存储会话中的整个params散列将耗尽服务器内存。此外,您应该在登录或退出用户之前重置会话,以避免会话固定。

我们确实遇到了一些问题 - 首先,如果用户(或机器人)从未登录,我们不想累积一堆“无人认领”的文章。最简单的方法是设置一个cron作业在没有关联用户的情况下删除特定年龄的文章。

您还希望在show / index操作中过滤没有用户的任何文章。