Weird has_many :through new record form issue - ruby-on-rails

I'm having a regular for with checkboxes for my has_many :through relation. My problem is that I can't create a new project and have checkboxes checked. I get a validation error "Users is invalid". This is really weird.
If I create a project with no user checked it works and I can check them when I'm editing the project.
- User.each do |user|
%label.checkbox{title: user.email}
= check_box_tag 'project[user_ids][]', user.id, #project.user_ids.include?(user.id)
= truncate(user.full_name, length: 16)
So in short: I can edit projects but not create new ones. Any ideas?
EDIT:
I have three models, User, Project, Projectship where the latest is the relation between the others. It's when I'm trying to create a project and pass user relations to it my problem occurs. When editing everything works like a charm.
User
id
email
has_many :projectships, dependent: :destroy
has_many :projects, through: :projectships
Project
id
name
has_many :projectships, dependent: :destroy
has_many :users, through: :projectships
Projectship
id
user_id
project_id
belongs_to :project
belongs_to :user
validates :project_id, presence: true
validates :user_id, presence: true
ProjectsController:
# GET /projects/new
def new
#project = Project.new
end
# POST /projects
def create
#project = Project.new(project_params)
if #project.save
redirect_to #project, notice: t('flash.project_created')
else
render :new
end
end
# GET /projects/:id/edit
def edit
#project = Project.includes(:users).find(params[:id])
end
# PUT /projects/:id
def update
#project = Project.find(params[:id])
if #project.update_attributes(project_params)
redirect_to :back, notice: t('flash.project_updated')
else
render :edit
end
end
private
def project_params
params.require(:project).permit(
:client_id, :currency, :description, :end_date, :estimated_hours,
:fixed_price, :hourly_rate, :name, :start_date, :status,
:billable_type, :user_ids
)
end
P.S I'm using 4.0.0.beta D.S

To store users_ids the model needs to be saved and that's way it didn't work. So now I store the ids in the create action and than add them directly after I save the project.

Related

Rails 5: Nested attributes aren't updated for model

I can't get rails to update my nested attributes, though regular attributes work fine. This is my structure:
unit.rb:
class Unit < ApplicationRecord
has_many :unit_skill_lists
has_many :skill_lists, through: :unit_skill_lists, inverse_of: :units, autosave: true
accepts_nested_attributes_for :skill_lists, reject_if: :all_blank, allow_destroy: true
end
unit_skill_list.rb:
class UnitSkillList < ApplicationRecord
belongs_to :unit
belongs_to :skill_list
end
skill_list.rb:
class SkillList < ApplicationRecord
has_many :unit_skill_lists
has_many :units, through: :unit_skill_lists, inverse_of: :skill_lists
end
And this is (part of) the controller:
class UnitsController < ApplicationController
def update
#unit = Unit.find(params[:id])
if #unit.update(unit_params)
redirect_to edit_unit_path(#unit), notice: "Unit updated"
else
redirect_to edit_unit_path(#unit), alert: "Unit update failed"
end
end
private
def unit_params
unit_params = params.require(:unit).permit(
...
skill_list_attributes: [:id, :name, :_destroy]
)
unit_params
end
end
The relevant rows in the form (using formtastic and cocoon):
<%= label_tag :skill_lists %>
<%= f.input :skill_lists, :as => :check_boxes, collection: SkillList.where(skill_list_type: :base), class: "inline" %>
Any idea where I'm going wrong? I have tried following all guides I could find but updating does nothing for the nested attributes.
Edit after help from Vasilisa:
This is the error when I try to update a Unit:
ActiveRecord::RecordInvalid (Validation failed: Database must exist):
This is the full unit_skill_list.rb:
class UnitSkillList < ApplicationRecord
belongs_to :unit
belongs_to :skill_list
belongs_to :database
end
There is no input field for "database". It is supposed to be set from a session variable when the unit is updated.
If you look at the server log you'll see something like skill_list_ids: [] in params hash. You don't need accepts_nested_attributes_for :skill_lists, since you don't create new SkillList on Unit create/update. Change permitted params to:
def unit_params
params.require(:unit).permit(
...
skill_list_ids: []
)
end
UPDATE
I think the best options here is to set optional parameter - belongs_to :database, optional: true. And update it in the controller manually.
def update
#unit = Unit.find(params[:id])
if #unit.update(unit_params)
#unit.skill_lists.update_all(database: session[:database])
redirect_to edit_unit_path(#unit), notice: "Unit updated"
else
redirect_to edit_unit_path(#unit), alert: "Unit update failed"
end
end

Location model as polymorphic association

I hope I'm forming this question correctly. But I'm trying to create a location model that has a geocoded address and that address is able to be located on a map using gmap for rails.
My issue is associating my Location model with other application models. Currently I'm attempting to have a location field within my post form.
My application is as followed using the geocoder and gmaps for rails gems.
class Location < ActiveRecord::Base
belongs_to :locatable, polymorphic: true
belongs_to :post
geocoded_by :address
acts_as_gmappable
after_validation :geocode
validates :address, presence: true
validates :latitude, presence: true
validates :longitude, presence: true
def gmaps4rails_address
"#{address}"
end
validates :locatable, presence: true
end
Post model
class Post < ActiveRecord::Base
has_one :location, as: :locatable , :dependent => :destroy
accepts_nested_attributes_for :locations,:reject_if =>:all_blank ,allow_destroy: true
end
Controllers
Post Controller
def new
#post= current_user.posts.build
end
def create
#post = current_user.posts.new(post_params)
#post = Location.new
if #post.save
redirect_to root_path
else
render 'new'
flash[:error] = !"
end
end
def post_params
params.require(:post).permit(locations_attributes[:address,:latitude,:longitude, :locatable_id, :locatable_type, :gmaps])
end
Locations Controller
class LocationsController < ApplicationController
def new
#location = Location.new
end
def create
#location = Location.new(params[:location])
end
def destroy
#location.destroy
respond_to do |format|
format.html { redirect_to locations_url, notice: 'Location was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def location_params
params.require(:location).permit(:address, :latitude, :longitude, :locatable_id, :locatable_type, :gmaps)
end
end
My code might be snippet out but my overall issue is happening within the controller I have everything going right. The location field within my post form is a nested form of the model location, the address field is geocoded and has a location search for the address input. My problem arises when submitting the post, I've tried several methods but I cannot get the location to save to post model. Any help would be amazingly helpful.

Rails 4 - Has_many, Using Nested Form to Edit a Specfic Record

I have a User who has many Accounts through a User_Accounts model. The User_Accounts model also tracks other information such as admin and billing access. Via the user edit form, I want to be able to edit the admin and billing boolean fields for the users current account.
user.rb
class User < ActiveRecord::Base
has_one :owned_account, class_name: 'Account', foreign_key: 'owner_id'
has_many :user_accounts
has_many :accounts, through: :user_accounts
accepts_nested_attributes_for :user_accounts
end
user_account.rb
class UserAccount < ActiveRecord::Base
belongs_to :account
belongs_to :user
end
In the users controller, I specified which user_account I wanted to edit via the nested form and assigned to the #user_account instance variable.
users_controller.rb
def edit
#user = User.find(params[:id])
#user_account = #user.user_accounts.find_by_account_id(current_account)
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
redirect_to #user, notice: 'User was successfully updated.'
else
render action: "edit"
end
end
private
def user_params
params.require(:user).permit(:name, :email, user_accounts_attributes: [:admin, :billing] )
end
user/edit.html.erb
<%= f.fields_for :user_accounts, #user_account do |o| %>
<%= o.check_box :admin, class: 'checkbox' %>
<% end %>
When I submit the change, it successfully saves the user record, but doesn't update the User_account record. It appears to be passing the following:
{"name"=>"Colin 21", "email"=>"mike21#example.com", "user_accounts_attributes"=>{"0"=>{"admin"=>"1"}}}
Id is required to edit an object via accepts_nested_attributes_for. Seems that the id attribute is not allowed through strong parameters.
Try changing the user_params method in 'users_controller.rb'
def user_params
params.require(:user).permit(:name, :email, user_accounts_attributes: [:id, :admin, :billing] )
end
You need to add a hidden field for user account's id field within fields_for part of the form too.

dynamic nested form always creates an extra blank entry - using formtastic_coocoon

I'm using formtastic & formtastic_cocoon to created a nested form.
All seems to be working well dynamically adding a nested form to an existing form, with one exception.
I have users and users have entries.
When I create a user, and add an entry, I end up with
-User
- Entry (empty)
- Entry Test 1
I should only have
-User
- Entry Test 1
I'm not sure why the blank entry is always showing up.
My models are
class User < ActiveRecord::Base
validates :name, :presence => true
has_attached_file :photo
has_many :tasks, :dependent => :destroy
accepts_nested_attributes_for :tasks, :allow_destroy => true
end
class Task < ActiveRecord::Base
attr_accessible :entry
belongs_to :user
end
my create controller is (I think this is the right controller)
def create
#user = User.new(params[:user])
if #user.save
flash[:notice] = "Successfully created user."
redirect_to #user
else
render :action => 'new'
end
end
def create
#task = Task.new(params[:task])
if #task.save
flash[:notice] = "Successfully created task."
redirect_to #task
else
render :action => 'new'
end
end
The empty entries are showing up in the database, so I don't think it is a problem with the html.erb files, but I can post those here if that would help.
Turns out this may be an issue with the way formtastic_cocoon handles forms.
When looking at the html source, the nested form is in the page, but hidden.
I changed the model to
accepts_nested_attributes_for :tasks, :reject_if=> proc {|attributes| attributes[:entry].blank?}, :allow_destroy => true

Error creating a new survey as the associated model(s) are invalid (questions)

I have a survey as part of an application I'm building. The user can create a survey and specify questions dynamically (can have as many as they want), so I've used an associated model with:
#survey.rb
has_many :survey_questions, :dependent => :destroy
has_many :survey_answers, :dependent => :destroy
after_update :save_survey_questions
validates_associated :survey_questions
def save_survey_questions
survey_questions.each do |t|
if t.should_destroy?
t.destroy
else
t.save(false)
end
end
end
def survey_question_attributes=(survey_question_attributes)
survey_question_attributes.each do |attributes|
if attributes[:id].blank?
survey_questions.build(attributes)
else
survey_question = survey_questions.detect { |e| e.id == attributes[:id].to_i }
survey_question.attributes = attributes
end
end
end
#surveys_controller.rb
def new
#survey = Survey.new
if(#survey.survey_questions.empty?)
#survey.survey_questions.build
end
respond_to do |format|
format.html # new.html.erb
end
end
def create
#survey = Survey.new(params[:survey])
respond_to do |format|
if #survey.save
format.html { redirect_to(survey_path(:id => #survey)) }
else
format.html { render :action => "new" }
end
end
end
#survey_question.rb
class SurveyQuestion < ActiveRecord::Base
belongs_to :survey
attr_accessor :should_destroy
def should_destroy?
should_destroy.to_i == 1
end
validates_presence_of :question, :survey_id
end
The problem is when I submit I get an error on the questions:
#errors={"survey_questions"=>["is invalid", "is invalid", "is invalid"]}
I believe it is because the survey_id I have linking surveys to survey_questions is not being filled in.
Any ideas how I can overcome this?
If I create the survey with no questions, then add them afterwards via edit, then it works perfectly.
I'm pretty sure that accepts_nested_attributes can help you a lot, there you'll find some examples building the associated objects wich seems to be your problem (since the survey_id in survey_questions is not being filled in), basically you should define in your models something like:
class Survey < ActiveRecord::Base
has_many :survey_questions
accepts_nested_attributes_for :survey_questions, :allow_destroy => true
...
end
It will handle all the SurveyQuestions validations through Survey.
Your code looks close to the standard --> http://railscasts.com/episodes/75-complex-forms-part-3
Are you sure you are getting the question parameter back correctly? I only ask because that is the other thing you are validating against and you don't have the form code in there so I can't see what's coming back to the controller.
OK,
I've managed to fix it and it was a really silly mistake on my part.
In survey_question.rb I had the line :
validates_presence_of :question, :survey_id
However, rails automatically deals with survey_id because of the has_many belongs_to relationship!
So this should be validates_presence_of :question
I also in the process of finding this out upgraded rails to 2.3.4 and started using:
accepts_nested_attributes_for :survey_questions, :allow_destroy => true
which dealt with all the attributes etc.

Resources