简体   繁体   English

Rails 4-如果不使用'has_one'关联创建新的嵌套模型,则无法保存模型

[英]Rails 4 - Can't save model without creating new nested model with 'has_one' association

I have a Visibility model, which has some boolean attributes and other things defining how other models can be seen. 我有一个可见性模型,该模型具有一些布尔属性和定义其他模型如何显示的其他内容。 Visibility is polymorphic, because I want it to belong to both the User and Activity models. 可见性是多态的,因为我希望它既属于User模型又属于Activity模型。 Visibility: 能见度:

class Visibility < ActiveRecord::Base  
  belongs_to :viewable, :polymorphic => true
end

User (edited to include totality): 用户(已编辑为包括总数):

class User < ActiveRecord::Base
  # Relations
  #has_many :posts
  has_one :fb_connection
  has_many :activities
  has_many :participations
  has_many :activities, :through => :participations
  has_one :visibility, as: :viewable, dependent: :destroy
  accepts_nested_attributes_for :visibility

  has_many :friendships
  has_many :friends, :through => :friendships
  has_many :sent_friend_invites, :through => :friendships
  has_many :received_friend_invites, :through => :friendships

  devise :database_authenticatable, :registerable,
  :recoverable, :rememberable, :trackable, :validatable, :confirmable

  # Callback to set a user's default visibility for their activities
  before_save :default_values

  # paperclip helper method
  has_attached_file :profile_pic, styles: {
    thumb: '100x100>',
    square: '200x200#',
    medium: '300x300>'
  }, default_url: "https://dl.dropboxusercontent.com/u/743320/q_silhouette.gif"


  # Pagination
  paginates_per 100

  # Validations
  # :email
  validates :first_name, presence: true
  validates :last_name, presence: true
  validates_format_of :email, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i

  # Paperclip validation
  validates_attachment :profile_pic, :size => { :in => 0..10.megabytes }, :content_type => { :content_type => /^image\/(jpeg|png|gif|tiff)$/}

  def self.paged(page_number)
    order(admin: :desc, email: :asc).page page_number
  end

  def self.search_and_order(search, page_number)
    if search
      where("email LIKE ?", "%#{search.downcase}%").order(
      admin: :desc, email: :asc
      ).page page_number
    else
      order(admin: :desc, email: :asc).page page_number
    end
  end

  def self.last_signups(count)
    order(created_at: :desc).limit(count).select("id","email","created_at")
  end

  def self.last_signins(count)
    order(last_sign_in_at:
    :desc).limit(count).select("id","email","last_sign_in_at")
  end

  def self.users_count
    where("admin = ? AND locked = ?",false,false).count
  end

  def get_display_name
    if display_name =~ /./  # Just check that the display name is not ""
      #puts "display name: " + display_name
      return display_name
    else
      #puts "name: " +  [first_name, last_name].join(" ")
      return [first_name, last_name].join(" ")
    end
  end

  def get_profile_pic_thumb
    return profile_pic(:thumb)
  end

  def measurement_labels
    return I18n.t('user_label_use_metric_true') if use_metric      
  end

  private

  def default_values
    viewable ||= Visibility.create(default_viewable_params)  
  end

  def default_viewable_params
    {:public => true, :app_friends => true, :facebook_friends => true, :strava_friends => true, :viewable => self }
  end
end

Activity (relevant parts): 活动(相关部分):

class Activity < ActiveRecord::Base
    ...  
    has_one :visibility, as: :viewable, dependent: :destroy
    ...
end

I can't for the life of me get this to work. 我一辈子都做不到。 Any time I just save a user model -- even if the Visibility model is not modified -- it creates a NEW Visibility model for the user. 任何时候只要保存用户模型(即使未修改可见性模型),它都会为用户创建一个新的可见性模型。 Eg, in the console: 例如,在控制台中:

user = User.find(5)
user.foo = false
user.save

I get this output: 我得到以下输出:

(0.4ms) BEGIN SQL (1.0ms) INSERT INTO "visibilities" ("public", "app_friends", "facebook_friends", "viewable_id", "viewable_type", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["public", "t"], ["app_friends", "t"], ["facebook_friends", "t"], ["viewable_id", 5], ["viewable_type", "User"], ["created_at", "2015-10-23 23:06:57.431922"], ["updated_at", "2015-10-23 23:06:57.431922"]] (21.3ms) COMMIT => true (0.4ms)BEGIN SQL(1.0ms)插入“可见性”(“ public”,“ app_friends”,“ facebook_friends”,“ viewable_id”,“ viewable_type”,“ created_at”,“ updated_at”)值($ 1,$ 2, $ 3,$ 4,$ 5,$ 6,$ 7)返回“ id” [[“ public”,“ t”],[“ app_friends”,“ t”],[“ facebook_friends”,“ t”],[“ viewable_id”, 5],[“ viewable_type”,“用户”],[“ created_at”,“ 2015-10-23 23:06:57.431922”],[“ updated_at”,“ 2015-10-23 23:06:57.431922”] ](21.3ms)COMMIT => true

And naturally, trying to update the Visibility model through User fails. 当然,尝试通过用户更新可见性模型失败。 While it is updated, a new one is also created in its place. 在更新时,也会在其位置创建一个新的。 Here is the applicable user_controller methods and view using simple_form_for: 这是适用的user_controller方法和使用simple_form_for的视图:

#user_controller
def preferences
    @user = current_user
    if !@user.visibility
      @user.visibility = Visibility.new
    end   
end

def update_preferences
    user = current_user
    user.update!(user_pref_params)
    flash[:notice] = I18n.t('user_flash_update_success')
    redirect_to profile_path(user)    
end

private 

def user_pref_params
    params.require(:user).permit(:use_metric, visibility_attributes: [:id, :public, :app_friends, :facebook_friends])
end

<!-- preferences form -->
<%= simple_form_for @user, :url => update_preferences_path do |f| %>            
    <%= f.simple_fields_for :visibility do |v| %>
        <%= v.input :public, label: t('user_preferences_label_public'), as: :select, required: false %>
        <%= v.input :app_friends, label: t('user_preferences_label_app_friends'), as: :select, required: false %>
        <%= v.input :facebook_friends, label: t('user_preferences_label_facebook_friends'), as: :select, required: false %>     
    <% end %>
    <!-- Preference for system of measurement -->
    <%= f.input :use_metric, as: :select, collection: [[t('user_preferences_use_metric_true'), true], [t('user_preferences_use_metric_false'), false]], label: t('user_preferences_label_use_metric'),  include_blank: false %> 

    <!-- Submit button -->
    <%= f.button :submit, :label => "Save", :class => "btn btn-primary" %>
<% end %>

This attempt at mass assignment gives me this feedback: 这种大规模分配的尝试给了我以下反馈:

Started PATCH "/users/updateprefs" for 127.0.0.1 at 2015-10-23 17:02:52 -0700 Processing by UsersController#update_preferences as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"FXj3kWxNDE7tl7InvBvL68UzlvmWR/d3aJ4/gTg7cCCEGEafJJZO10ud31kU2120SdKF3aNj5gy0FiizURHTeQ==", "user"=>{"visibility_attributes"=>{"public"=>"false", "app_friends"=>"false", "facebook_friends"=>"false", "id"=>"64"}, "use_metric"=>"true"}, "commit"=>"Update User"} User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 55]] (0.3ms) BEGIN Visibility Load (0.8ms) SELECT "visibilities".* FROM "visibilities" WHERE "visibilities"."viewable_id" = $1 AND "visibilities"."viewable_type" = $2 LIMIT 1 [["viewable_id", 55], ["viewable_type", "User"]] SQL (0.6ms) INSERT INTO "visibilities" ("public", "app_friends", "facebook_friends", "viewable_id", "viewable_type", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["public", "t"], ["a 从2015年10月23日17:02:52 -0700开始为127.0.0.1的PATCH“ / users / updateprefs”,由UsersController#update_preferences作为HTML参数进行处理:{“ utf8” =>“✓”,“ authenticity_token” =>“ FXj3kWxNDE7tl7InvBvL68UzlvmWR / d3aJ4 / gTg7cCCEGEafJJZO10ud31kU2120SdKF3aNj5gy0FiizURHTeQ =“ =” “” =>“ 64”},“ use_metric” =>“ true”},“提交” =>“更新用户”}用户负载(0.4毫秒)选择“用户”。*来自“用户”,而“用户”。 id“ = $ 1 ORDER BY” users“。” id“ ASC LIMIT 1 [[” id“,55]](0.3ms)开始可见性负载(0.8ms)选择“ visibilities”。*从“ visibilities”中选择“ visibilities” 。“ viewable_id” = $ 1和“ visibilities”。“ viewable_type” = $ 2 LIMIT 1 [[“” viewable_id“,55],[” viewable_type“,” User“]] SQL(0.6ms)插入“ visibilities”(“ public “,” app_friends“,” facebook_friends“,” viewable_id“,” viewable_type“,” created_at“,” updated_at“)值($ 1,$ 2,$ 3,$ 4,$ 5,$ 6,$ 7)返回“ id” [[[” public “,” t“],[” a pp_friends", "t"], ["facebook_friends", "t"], ["viewable_id", 55], ["viewable_type", "User"], ["created_at", "2015-10-24 00:02:52.244397"], ["updated_at", "2015-10-24 00:02:52.244397"]] SQL (0.5ms) UPDATE "users" SET "use_metric" = $1, "updated_at" = $2 WHERE "users"."id" = $3 [["use_metric", "t"], ["updated_at", "2015-10-24 00:02:52.247304"], ["id", 55]] SQL (0.5ms) UPDATE "visibilities" SET "app_friends" = $1, "updated_at" = $2 WHERE "visibilities"."id" = $3 [["app_friends", "f"], ["updated_at", "2015-10-24 00:02:52.250120"], ["id", 64]] (13.3ms) COMMIT pp_friends“,” t“],[” facebook_friends“,” t“],[” viewable_id“,55],[” viewable_type“,” User“],[” created_at“,” 2015-10-24 00:02 :52.244397“],[” updated_at“,” 2015-10-24 00:02:52.244397“]] SQL(0.5ms)UPDATE” users“ SET” use_metric“ = $ 1,” updated_at“ = $ 2 WHERE” users“。 “ id” = $ 3 [[“” use_metric“,” t“],[” updated_at“,” 2015-10-24 00:02:52.247304“],[” id“,55]] SQL(0.5ms)UPDATE”可见性“ SET” app_friends“ = $ 1,” updated_at“ = $ 2,” visibilities“。” id“ = $ 3 [[”“ app_friends”,“ f”],[“ updated_at”,“ 2015-10-24 00:02: 52.250120“],[” id“,64]](13.3ms)提交

As you can see, Rails is both creating a new visibility and updating the existing one! 如您所见,Rails既创建了新的可见性,又更新了现有的可见性! I can maybe jerry-rig this to work around it with some really ugly code, but I would appreciate any help to keep my controller actions clean. 也许我可以用杰瑞(Jerry-rig)操纵它,用一些非常丑陋的代码来解决它,但是我希望能为保持控制器动作整洁提供任何帮助。

In your User model, in the default_values method, you're creating a new visibility and assigning it to viewable . User模型中,使用default_values方法创建新的可见性并将其分配给viewable However, this is scoped such that it is only available to the method, not the class as a whole (and thus does comparison against the method variable). 但是,此方法的作用域仅适用于方法,而不适用于整个类(因此可以与方法变量进行比较)。

Also, viewable is the correct usage of the association only in the Visibility model. 另外, viewable是仅在Visibility模型中的关联的正确用法。 In the User model, you will have to reference it as visibility . User模型中,您必须将其作为visibility引用。

What needs to be done is to use self to apply the comparison and assignment to the instance variable instead. 需要做的是使用self来将比较和赋值应用于实例变量。

def default_values
  self.visibility ||= Visibility.create(default_viewable_params)  
end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM