1

Я работаю над реализацией новой модели, принадлежащей одной из существующих моделей веб-приложений. В конце концов, я хочу создать вложенную форму. Я понимаю, что форма и сильные параметры могут иметь собственный набор проблем, но я в настоящее время изо всех сил пытаюсь заставить модели вести себя так, как я ожидал бы в консоли rails.Rails Вложенные атрибуты правильно назначают parent_id как индекс, но не назначают дополнительные атрибуты

Rails 4.2.7, Postgres DB

ОБНОВЛЕНИЕ - 10/3/16 - Тем не менее, пытаясь найти правильное решение, но внесли некоторые изменения

Наша работа с высшими учебными заведениями и районов, и это конкретный случай касается обследований и того, как опрос присваивается школе и округу. До сих пор обследование было отнесено к округу с моделью SurveyAssignment, а некоторые из линейной логики предполагали, что все школы в округе были также «назначены» на исследование. Теперь мы хотим добавить дополнительную детализацию в SurveyAssignment и разрешить определенную специфику на уровне школы.

Итак, я создал модель SchoolSurveyAssignment и начал получать бит на месте.

Вот соответствующая информация модель:

class District < ActiveRecord::Base 
    ... 
    has_many :schools, dependent: :destroy 
    has_many :survey_assignments, dependent: :destroy 
    ... 
end 

class School 
    ... 
    belongs_to :district 
    has_many :school_survey_assignments 
    has_many :survey_assignments, :through => :school_survey_assignments 

    ... 
end 

class SurveyAssignment 
    belongs_to :district 
    belongs_to :survey 
    has_one :survey_version, through: :survey 
    has_many :school_survey_assignments, inverse_of: survey_assignment 
    has_many :schools, :through => :school_survey_assignments 

    accepts_nested_attributes_for :school_survey_assignments 

    attr_accessor :survey_group, :survey_version_type, :survey_version_id, :school_survey_assignments_attributes 
    validates :survey_id, presence: true 
end 

class SchoolSurveyAssignment 
    belongs_to :survey_assignment, inverse_of: :school_survey_assignments 
    belongs_to :school 

    attr_accessor :school_id, :survey_assignment_id, :grades_affected, :ulc_affected 
    validates_presence_of :survey_assignment 
    validates :school_id, presence: true, uniqueness: {scope: :survey_assignment_id} 
end 

Соответствующий код контроллера:

class SurveyAssignmentsController < ApplicationController 
    before_action :set_district 
    before_action :set_survey_assignment, only: [:show, :edit, :update, :destroy] 

    respond_to :html, :json, :js 

    def new 
    @new_survey_assignment = SurveyAssignment.new() 
    @district.schools.each do |school| 
     @new_survey_assignment.school_survey_assignments.build(school_id: school.id) 
    end 
    end 

    def create 
    @survey_assignment = SurveyAssignment.new(survey_assignment_params) 
    if @survey_assignment.save 
     flash[:notice] = "Survey successfully assigned to #{@district.name}" 
    else 
     flash[:alert] = "There was a problem assigning this survey to #{@district.name}" 
    end 
    redirect_to district_survey_assignments_path(@district) 
    end 

    def survey_assignment_params 
    params.require(:survey_assignment).permit(:survey_id, :status, :survey_version_id, school_survey_assignments_attributes: [:id, :survey_assignment_id, :school_id, grades_affected: [], ulc_affected: []]).tap do |p| 
     p[:district_id] = @district.id 
     p[:school_year] = session[:selected_year] 
    end 
    end 

    def set_district 
    @district = District.find(params[:district_id]) 
    end 

Вот соответствующая информация схемы:

create_table "school_survey_assignments", force: :cascade do |t| 
    t.integer "survey_assignment_id" 
    t.integer "school_id" 
    t.integer "grades_affected",  default: [], array: true 
    t.string "ulc_affected",   default: [], array: true 
end 

add_index "school_survey_assignments", ["school_id"], name: "index_school_survey_assignments_on_school_id", using: :btree 
add_index "school_survey_assignments", ["survey_assignment_id"], name: "index_school_survey_assignments_on_survey_assignment_id", using: :btree 

create_table "survey_assignments", force: :cascade do |t| 
    t.integer "district_id" 
    t.integer "survey_id" 
    t.integer "status" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    t.integer "school_year" 
    t.integer "last_response_status_id" 
end 

add_index "survey_assignments", ["district_id"], name: "index_survey_assignments_on_district_id", using: :btree 

После того, как они были на месте, я шагнул в мою консоль рельсов и попытался:

2.3.1 :002 > sa1 = SurveyAssignment.create(district_id: 3, survey_id: 508, school_year: 2017) 
    (0.2ms) BEGIN 
SQL (0.7ms) INSERT INTO "survey_assignments" ("district_id", "survey_id", "school_year", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["district_id", 3], ["survey_id", 508], ["school_year", 2017], ["created_at", "2016-09-30 21:30:20.205144"], ["updated_at", "2016-09-30 21:30:20.205144"]] 
    (7.2ms) COMMIT 
=> #<SurveyAssignment id: 369, district_id: 3, survey_id: 508, status: nil, created_at: "2016-09-30 21:30:20", updated_at: "2016-09-30 21:30:20", school_year: 2017, last_response_status_id: nil> 
2.3.1 :003 > sa2 = SurveyAssignment.create(district_id: 3, survey_id: 508, school_year: 2017) 
    (0.3ms) BEGIN 
SQL (0.4ms) INSERT INTO "survey_assignments" ("district_id", "survey_id", "school_year", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["district_id", 3], ["survey_id", 508], ["school_year", 2017], ["created_at", "2016-09-30 21:30:30.701197"], ["updated_at", "2016-09-30 21:30:30.701197"]] 
    (0.5ms) COMMIT 
=> #<SurveyAssignment id: 370, district_id: 3, survey_id: 508, status: nil, created_at: "2016-09-30 21:30:30", updated_at: "2016-09-30 21:30:30", school_year: 2017, last_response_status_id: nil> 

Итак, теперь я успешно создал два задания съемки. Теперь я собираюсь создать два присвоений обследования школ прочь sa1:

2.3.1 :004 > [{school_id: 5}, {school_id: 6}].each do |ssa| 
2.3.1 :005 >  sa1.school_survey_assignments.create(ssa) 
2.3.1 :006?> end 
    (0.2ms) BEGIN 
SchoolSurveyAssignment Exists (2.4ms) SELECT 1 AS one FROM "school_survey_assignments" WHERE ("school_survey_assignments"."school_id" = 5 AND "school_survey_assignments"."survey_assignment_id" = 369) LIMIT 1 
SQL (0.4ms) INSERT INTO "school_survey_assignments" ("survey_assignment_id") VALUES ($1) RETURNING "id" [["survey_assignment_id", 369]] 
    (6.4ms) COMMIT 
    (0.6ms) BEGIN 
SchoolSurveyAssignment Exists (0.4ms) SELECT 1 AS one FROM "school_survey_assignments" WHERE ("school_survey_assignments"."school_id" = 6 AND "school_survey_assignments"."survey_assignment_id" = 369) LIMIT 1 
    SQL (0.3ms) INSERT INTO "school_survey_assignments" ("survey_assignment_id") VALUES ($1) RETURNING "id" [["survey_assignment_id", 369]] 
    (0.4ms) COMMIT 
=> [{:school_id=>5}, {:school_id=>6}] 
2.3.1 :007 > sa1.save 
    (0.3ms) BEGIN 
    (0.4ms) COMMIT 
=> true 

Теперь, похоже, я успешно создал два SchoolSurveyAssignments с survey_assignment_id = 369 и school_ids = 5 и 6

2.3.1 :008 > sa1.school_survey_assignments 
    SchoolSurveyAssignment Load (0.3ms) SELECT "school_survey_assignments".* FROM "school_survey_assignments" WHERE "school_survey_assignments"."survey_assignment_id" = $1 [["survey_assignment_id", 369]] 
=> #<ActiveRecord::Associations::CollectionProxy [#<SchoolSurveyAssignment id: 5, survey_assignment_id: 369, school_id: nil, grades_affected: [], ulc_affected: []>, #<SchoolSurveyAssignment id: 6, survey_assignment_id: 369, school_id: nil, grades_affected: [], ulc_affected: []>]> 

Как вы можете видеть из ActivRecord :: Associations :: CollectionProxy, оба объекта SchoolSurveyAssignments были созданы с помощью survey_assignment_id: 369, но с nil school_id. Это вызывает беспокойство, поскольку это, кажется,

  1. Игнорирование параметров, передаваемых в функцию создания и
  2. игнорируя проверку school_id

Другой вопрос, который я не понимаю, является следующее :

2.3.1 :009 > SchoolSurveyAssignment.find(5).survey_assignment_id 
    SchoolSurveyAssignment Load (0.6ms) SELECT "school_survey_assignments".* FROM "school_survey_assignments" WHERE "school_survey_assignments"."id" = $1 LIMIT 1 [["id", 5]] 
=> nil 
2.3.1 :011 > SchoolSurveyAssignment.find(5).survey_assignment.id 
    SchoolSurveyAssignment Load (0.3ms) SELECT "school_survey_assignments".* FROM "school_survey_assignments" WHERE "school_survey_assignments"."id" = $1 LIMIT 1 [["id", 5]] 
    SurveyAssignment Load (0.4ms) SELECT "survey_assignments".* FROM "survey_assignments" WHERE "survey_assignments"."id" = $1 LIMIT 1 [["id", 369]] 
=> 369 

Вызов .survey_assignment_id должен возвращать атрибут на SchoolSurveyAssignment и дать 369. .survey_assignment.id просто просто захватить bing идентификатор родительского объекта. Я ожидал бы, что оба возвращают одно и то же значение, но один возвращает nil.

В конце используется форма SurveyAssignment, которая позволяет пользователю установить атрибуты для нового объекта SurveyAssignment, а также установить атрибуты для X номера SchoolSurveyAssignments (в зависимости от количества школ в округе, варьируется от 2 до 15) , Как только я лучше пойму, как эти модели взаимодействуют, я уверен в выполнении этой цели, но поведение, которое я вижу, для меня не имеет смысла, и я надеялся найти определенную ясность в реализации этих связанных моделей. Я чувствую, что я подпрыгиваю вокруг ответа, но не хватает ключевой информации.

Спасибо,

Alex

+0

вы можете разместить код контроллера? Я полагаю, вы используете сильные параметры? – Ren

+0

Я использую сильные параметры. Я обновлю код контроллера. Это может привести к моему невежеству, но у меня сложилось впечатление, что методы контроллера только попадают в истинные HTTP-запросы/маршрутизацию, и что запуск команд из консоли не ударит по этим методам. –

ответ

1

Try удалив ваши коды attr_accessor. attr_accessor не должны использоваться для атрибутов, которые сохраняются в базе данных, и это, вероятно, портя методы, которые ActiveRecord уже обеспечивает по умолчанию, в результате чего эти атрибуты не могут быть сохранены правильно

class SurveyAssignment 
    belongs_to :district 
    belongs_to :survey 
    has_one :survey_version, through: :survey 
    has_many :school_survey_assignments, inverse_of: survey_assignment 
    has_many :schools, :through => :school_survey_assignments 

    accepts_nested_attributes_for :school_survey_assignments 

    validates :survey_id, presence: true 
end 

class SchoolSurveyAssignment 
    belongs_to :survey_assignment, inverse_of: :school_survey_assignments 
    belongs_to :school 

    validates_presence_of :survey_assignment 
    validates :school_id, presence: true, uniqueness: {scope: :survey_assignment_id} 
end 
+0

Привет, спасибо за помощь! Я попытался создать по вашему предложению, и он создает SurveyAssignment, но не school_survey_assignments. Я также пробовал, что говорят api.rubyonrails.org для примера один-ко-многим http://api.rubyonrails.org/v4.2/classes/ActiveRecord/NestedAttributes/ClassMethods.html#label -Validating + + + + + + + родитель + модель Это также привело к созданию сюжетного задания, но не к созданию объектов SchoolSurveyAssignments. –

+0

Основываясь на некоторых рекомендациях со стороны коллеги, я перешел к использованию пользовательского класса объектов класса Form, чтобы справиться с созданием задания Survey и SchoolSurveyAssignments. Это правильное обращение с параметрами, и я знаю, что получаю все необходимые параметры через SurveyAssignmentController и в этот объект. Однако он по-прежнему не сохраняет атрибуты дочерней модели (school_survey_assignment). Казалось бы, у меня есть какая-то другая проблема, а не любая проблема с вложенными формами/объектами формы. –

+0

сделал редактирование оригинального сообщения.попробуйте прокомментировать/удалить строки 'attr_accessor' – Ren

1

Для первого вопроса, школа и SurveyAssignment не знают друг друга, school_id становится нулевым. В вашем приложении эти модели имеют связь m-to-n косвенно, поэтому как насчет использования has_many посредством ассоциации между моделями?

В модели школы, добавьте ниже:

has_many :survey_assignments, :through => :school_survey_assignments 

В модели SurveyAssignments, добавьте ниже:

has_many :schools, :through => :school_survey_assignments 

Для последнего вопроса, оба кода, кажется, такой же ..

+0

спасибо за указание необходимой ассоциации. Я добавил это, и я все еще сталкиваюсь с некоторыми проблемами. Я обновил код, чтобы отразить изменения. Что касается последнего вопроса, разница в .id vs _id –

+0

Извините, я упустил это, но оба .id и _id работают на моем ПК. Является ли ваша проблема еще .id vs _id? BTW, в классе SurveyAssignment, inverse_of: survey_assignment отсутствует ':' до 'survey_assignment', я думаю. – YTorii

+0

Спасибо за продолжение. Это пропало: это была опечатка, переходящая от моего редактора к Stackoverflow, но хорошая уловка. –

 Смежные вопросы

  • Нет связанных вопросов^_^