【问题标题】:Can't save form_for one controller in view partial, rails 4无法在视图部分中保存 form_for 一个控制器,rails 4
【发布时间】:2016-06-18 23:27:58
【问题描述】:

这已经被问过很多了,但我找不到任何非常适用的东西。我要做的是在UsersController 的编辑视图中为SettingsController 呈现一个编辑表单。我对 RoR 非常陌生,所以我什至不确定自己做错了什么。

This 问题似乎最接近,但是当我在Users 控制器中初始化@setting = Setting.new 时,我得到一个Settings 表单,没有为迁移中的新用户设置默认值。但是如果我初始化@setting = Setting.editSetting.update,我会得到一个未定义的方法或错误数量的参数错误。

Setting.new 表单被保存时,它会抛出这个错误:

SettingsController 中 find_by_id 的未定义方法:app/controllers/settings_controller.rb:43:in `correct_user'。

当我检查数据库时,在创建用户时设置记录正在正确创建,但在保存表单时设置记录没有更新。

setting.rb:

class Setting < ActiveRecord::Base
  belongs_to :user
  validates :user_id, presence: true
end

user.rb:

class User < ActiveRecord::Base
  has_many :posts, dependent: :destroy
  has_one  :setting, dependent: :destroy
  after_create :create_setting
end

用户控制器:

 class UsersController < ApplicationController
 before_action :logged_in_user, only: [:edit, :update, :index, :destroy]
 before_action :correct_user, only: [:edit, :update]
 before_action :admin_user, only: :destroy

 def new
   @user = User.new
 end

 def edit
   @user = User.find(params[:id])
   @setting = Setting.update
 end

 def update
   @user = User.find(params[:id])
   @setting = Setting.update
   if @user.update_attributes(user_params)
     flash[:success] = "Profile updated!"
     redirect_to @user
   else
     render 'edit'
   end
 end

 def settings
   @title = "Settings"
   @setting = Setting.find_by_user_id(params[:user_id])
 end

private

 def user_params
     params.require(:user).permit(:name, :email, :password,
                               :password_confirmation)
 end

 # Confirms the correct user.
 def correct_user
   @user = User.find(params[:id])
   redirect_to(root_url) unless current_user?(@user)
 end
end

设置控制器:

class SettingsController < ApplicationController
 before_action :logged_in_user, only: [:create, :edit, :update, :show, :index]
 before_action :correct_user, only: [:create, :edit, :update, :show, :index]

 def index
   @settings = Setting
 end

 def show
   @setting = User.find(params[:id]).setting
 end

 def new
   @setting = Setting.new
 end

 def edit
   @setting = Setting.find(params[:id])
 end

 def create
    @setting = current_user.settings.build(setting_params)
    @setting.save
 end

 def update
   @setting = Setting.find(params[:id])
   if @setting.update_attributes(post_params)
     flash[:success] = "Settings updated!"
     redirect_to request.referrer
   else
     render 'edit'
   end
 end

 private

 def setting_params
   params.require(:setting).permit(:reading_theme)
 end

 def correct_user
   @setting = current_user.setting.find_by_id(params[:id]) ##the line which throws an error when the form is saved
   redirect_to root_url if @setting.nil?
 end
end

表格部分:

 <%= form_for(@setting) do |f| %>
   <%= render 'shared/error_messages', object: f.object %>
     <div class="field">
       <%= radio_button_tag(:reading_theme, "flatly") %>
       <%= label_tag(:reading_theme_flatly, "Light (Default)") %>
     </div>
     <div class="field">
       <%= radio_button_tag(:reading_theme, "darkly") %>
       <%= label_tag(:reading_theme_darkly, "Dark") %>
     </div>
   <%= f.submit yield(:button_text), class: "btn btn-primary" %>
 <% end %>

routes.rb:

 resources :users do
   member do
     get :following, :followers
   end
 end
 resources :settings, only: [:new, :create, :edit, :update]
 ...

ETA:设置迁移:

class CreateSettings < ActiveRecord::Migration
  def change
    create_table :settings do |t|
      t.string :reading_theme, default: => "flatly"
      t.references :user, index: true, foreign_key: true

      t.timestamps null: false
    end
  end
end

如何获得正确的默认值以便正确保存我的表单?

【问题讨论】:

  • 请包括您提到的迁移,尤其是默认值。这将在您的项目环境中得出合适的答案。
  • @MichaelGaskill,刚刚添加了它
  • 我刚刚在new 操作中将其添加到我的答案中。

标签: ruby-on-rails ruby ruby-on-rails-4 activerecord


【解决方案1】:

您为迁移中的字段包含的任何默认值对于 Ruby 中的模型类(设置)都是“未知的”。 Ruby(或者更确切地说是 Rails ActiveRecord)在创建模型对象时不会从表定义中读取默认值。这可能会导致您在此处看到的双重人格问题。

您需要做的是在适当的情况下将相关的默认值添加到 Ruby 代码中。例如,在您的设置控制器中,您可以进行以下更改:

def new
  @setting = Setting.new
  # Set any defaults that will be visible to the user on the form
  @setting.reading_theme = "flatly"
  # The form will allow the user to choose their own values, based on the defaults
end

def create
  @setting = current_user.settings.build(setting_params)
  # Set any defaults that will NOT be visible to the user
  @setting.save
end

这使您能够区分对用户可见的默认值和不可见的默认值。

请注意,您还可以在创建模型对象时选择建立默认值,但这在某些情况下可能会更复杂,并且在实际使用中似乎不太常见。 How to initialize an ActiveRecord with values in Rails? 中有一个 SO 答案,以防这更适合您的需求。

【讨论】:

  • 谢谢!因此,在这个答案和@DennisCastro 的答案之间,表单正在呈现并且在保存时不再抛出错误,但它也没有保存到数据库中。我想我没有正确理解 def new 和 def create 需要更改的地方——我假设在 UsersController 中?因为如果我在 SettingsController 中更改它们,我会继续收到 nil 参数错误。除了将它们添加到 UsersController 似乎会创建一个空表单并且不保存任何内容。我觉得我错过了一些简单的东西。
  • @JimHogan 我更新了我的答案,说应该对设置控制器进行更改。请注意,DennisCastro 的答案不应应用于newcreate 操作,因为这是专门用于editshow 操作的方法。正如您的“零参数错误”所证明的那样,您的代码可能需要解决其他问题才能获得完整的解决方案,并且您必须使用相关的错误详细信息更新您的问题(整个操作日志,包括堆栈跟踪)以便能够弄清楚这些。
【解决方案2】:

不能在 has_one 关系中使用 find_by_id

@setting = current_user.setting.find_by_id(params[:id])

只需@setting = current_user.setting

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-06
    相关资源
    最近更新 更多