【问题标题】:How to store data in session from multiple models?如何将来自多个模型的数据存储在会话中?
【发布时间】:2015-11-01 17:08:32
【问题描述】:

使用help of @blnc,我们能够将用户的目标存储在他的会话中。然后在他注册后,将该目标保存到他的新帐户并从会话中删除。

作为注册过程中的一个附加步骤,我希望用户在能够注册之前也养成一种习惯。

goals_controller

  def create
    if current_user == nil
        # If there is no user, store the goal values to the session
        session[:goal_name] = goal_params[:name]
        session[:goal_deadline] = goal_params[:deadline]
        redirect_to signup_url
    else
        @goal = current_user.goals.build(goal_params)
        if @goal.save
            track_activity @goal
            redirect_to @goal, notice: 'Goal was successfully created'
        else
            flash.now[:danger] = 'Required Field: "Enter Goal"'
            render 'new'
        end
    end

我模仿了存储目标的操作,但它不起作用。当用户创建他的目标,然后是习惯,然后注册时,在看到他的新帐户时,只存储了目标。这种习惯从未被保存下来。当我在控制台中搜索它时,它甚至都不存在。

我做错了什么?

habits_controller

  def create
    if current_user == nil
      # If there is no user, store the goal values to the session.
      session[:habit_committed] = habit_params[:committed => []]
      session[:habit_date_started] = habit_params[:date_started]
      session[:habit_trigger] = habit_params[:trigger]
      session[:habit_action] = habit_params[:action]
      session[:habit_target] = habit_params[:target]
      session[:habit_reward] = habit_params[:reward]
      session[:habit_order] = habit_params[:order]
      redirect_to signup_url
    else
      @habit = current_user.habits.build(habit_params)
      if @habit.conceal == true
        @habit.save_with_current_level
        redirect_to @habit, notice: 'Habit was successfully created'
      elsif
        @habit.save_with_current_level
        track_activity @habit
        redirect_to @habit, notice: 'Habit was successfully created'
      else
        flash.now[:danger] = 'Required Fields: "Committed to", "Started", and "Enter Habit"'
        render 'new'
      end
    end
  end

  def new
    if current_user == nil
      @habit = Habit.new
    else
      @habit = current_user.habits.build
    end
  end

users_controller

  def create
    @user = User.new(user_params)
    if @user.save
      # Grab the session variable at the same time deleting it
      name = session.delete(:goal_name)
      deadline = session.delete(:goal_deadline)
      committed = session.delete(:habit_committed)
      date_started = session.delete(:habit_date_started)
      trigger = session.delete(:habit_trigger)
      action = session.delete(:habit_action)
      target = session.delete(:habit_target)
      reward = session.delete(:habit_reward)      
      #You can make this more complex for error handling
      @user.goals.create(name: name, deadline: deadline)
      @user.habits.create(committed: committed, date_started: date_started, trigger: trigger, action: action, target: target, reward: reward)
      @user.send_activation_email
      flash[:info] = "Please check your email to activate your account."
      redirect_to root_url
    else
      render 'new'
    end
  end

在我发布一个习惯后从终端

Started POST "/habits" for 127.0.0.1 at 2015-08-09 16:56:20 -0400
Processing by HabitsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"IWbim9fUlU0Ix43Z+WGpJkKhbhPyM7o0JeZ1KFY1X5ugGukOs6asvRatior0c7vBfmaRiNmKkl9O1bka5Bdrcg==", "habit"=>{"committed"=>["sun", "mon", "tue", "wed", "thu", "fri", "sat", ""], "date_started(2i)"=>"8", "date_started(3i)"=>"9", "date_started(1i)"=>"2015", "trigger"=>"", "action"=>"test", "target"=>"", "reward"=>"", "tag_list"=>"", "conceal"=>"0"}, "button"=>""}
Redirected to http://0.0.0.0:3000/signup
Completed 302 Found in 11ms (ActiveRecord: 0.0ms)


Started GET "/signup" for 127.0.0.1 at 2015-08-09 16:56:21 -0400
Processing by UsersController#new as HTML
  Rendered shared/_error_messages.html.erb (0.1ms)
  Rendered users/new.html.erb within layouts/application (3.8ms)
  Rendered layouts/_header.html.erb (0.4ms)
Completed 200 OK in 1047ms (Views: 1046.2ms | ActiveRecord: 0.0ms)

【问题讨论】:

  • 嗯我不喜欢这段代码,因为你没有检查习惯和目标是否保存成功。而且因为你重定向,你永远不会知道发生了什么。

标签: ruby-on-rails ruby session model-view-controller


【解决方案1】:

在创建习惯和目标实例时,您的代码不会检查可能的错误,很可能是一个简单的错误会阻止验证,从而阻止数据库中的持久性。即

  @user = User.new(user_params)
    if @user.save
      ...
      @user.goals.create(...) # What if it fails ?
      @user.habits.create(...) # What if it fails ?
      @user.send_activation_email
      ...
      redirect_to root_url
    else
      render 'new'
    end

如果注释行失败,您将不会有任何反馈,因为您将重定向_到另一个页面。 如果这些行成功(=return false),它们将保存目标/习惯,但如果它们失败(并返回 false),那么其余的过程将正常执行

你应该这样做:

@user = User.new(user_params)
    if @user.save
      ...
      unless @user.goals.create(...) # unless = if not
        # The warnings variable will be used for user notification
        (warnings ||= []) << "Warning ! Goal was not saved because of validation errors"
        # Use Rails logger for administrative detection of errors
        # => (Rails.logger .warning, .error, .info, .debug) will add to the `rails_root/log/#{environment}` log file, depending on the `:log_level` selected in your configuration
        Rails.logger.warn("Warning, auto-creation of Goal for user #{@user.name} on sign_up failed !")
      end
      unless @user.habits.create(...) # What if it fails ?
        (warnings ||= []) << "Warning ! Habit was not saved because of validation errors"
        Rails.logger.warn("Warning, auto-creation of Habit for user #{@user.name} on sign_up failed !")
      end

      @user.send_activation_email
      ...
      flash[:warning] = warnings.join('<br>').html_safe if warnings # Assuming you have some HTML code that renders flash[:warning]
      redirect_to root_url
    else
      render 'new'
    end

当然,你也可以使用类似的东西来说明它失败的原因

unless goal= @user.goals.create(...)
  (warnings ||= []) << "Warning ! Goal was not saved because of validation errors : #{goal.errors.map{|k,v| "#{k} : #{v}"}.join('<br>')"
end

【讨论】:

  • 你能分析一下在你重定向到之前会发生什么吗?使用像 byebug 这样的调试器,或者只是在调用 redirect_to 之前打印目标 puts goal
  • 是的,是的,我有点复制了目标/习惯的代码,即使你说目标现在工作得很好,因为对我来说,有一些代码可能会被忽视而感觉很糟糕。即,目前goal 可以正确保存/存储,但将来如果不正确,您甚至都不会注意到它。我将进行编辑以展示如何使用 Rails 记录器。
  • 是的,在redirect to new_habit_path 之前尝试puts goal。如果有任何验证错误,应该显示出来。或者直接写puts goal.errors
猜你喜欢
  • 2015-09-25
  • 2021-10-23
  • 1970-01-01
  • 2020-10-02
  • 2011-10-29
  • 1970-01-01
  • 1970-01-01
  • 2014-03-30
  • 1970-01-01
相关资源
最近更新 更多