I'm trying to create two model in just one form. I have user and unit model both are associated with has_many :through association.
user.rb
class User < ActiveRecord::Base
has_many :units, :through => :user_unit_assocs
has_many :user_unit_assocs
end
unit.rb
class Unit < ActiveRecord::Base
has_many :users, :through => :user_unit_assocs
has_many :user_unit_assocs
end
users_controller.rb
class UsersController < ApplicationController
def create
#user = User.new(user_params)
#user.units.build
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
else
format.html { render :new }
end
end
end
private
def user_params
params.require(:user).permit(:username, :email, units_attributes:[:unitname])
end
end
This is my form, users new
<%= simple_form_for(#user) do |f| %>
<%= f.simple_fields_for :units do |unit| %>
<%= unit.input :unitname, required: true %>
<% end %>
<%= f.input :name, required: true %>
<%= f.input :email, required: true %>
<%= f.button :submit %>
<% end %>
When I run the code, the form only showing a input-field for :name and :email and there is no input-field for units:[:unitname]. How can I show the input-field in the form? Thanks in advance.
References:
1. Rails 4: accepts_nested_attributes_for and mass assignment
2. https://github.com/plataformatec/simple_form/wiki/Nested-Models
Add
def new
#user = User.new
#user.units.build
end
on your controller
You need to build the association in the new action, not the create action.
Related
I am trying to automatically create a child record (Participant) when I create a parent (Project) record. I can create the parent (Project) fine and, on other forms, I can create the child (Participant). I cannot seem to create the child (Participant) at the same time as the parent.
I am on Rails 4, and so I've set my strong params carefully. I just don't understand what I'm doing wrong.
Parent Controller:
class ProjectsController < ApplicationController
def new_project
#title = params[:ti]
#project = Project.new
#project.participants.build
end
def create_project
#project = Project.new(project_params)
#template = Template.find(params[:t])
#project.participants.build
#title = params[:ti]
respond_to do |format|
if #project.save
#project.participants.save
format.html { redirect_to new_milestones_path(:p => #project.id), notice: 'Great! We saved your project details.' }
else
format.html { redirect_to new_project_path(t: #template.id, ti: #title)
}
format.json { render json: #project.errors, status: :unprocessable_entity }
end
end
end
def project_params
params.require(:project).permit( :id, :title, :starts, participants_attributes: [:id, :email, :title, :status, :project_id])
end
end
Models:
class Participant < ActiveRecord::Base
belongs_to :project, inverse_of: :participants
........
end
class Project < ActiveRecord::Base
has_many :participants, dependent: :destroy, inverse_of: :project
accepts_nested_attributes_for :participants, allow_destroy: true, reject_if: proc { |a| a["email"].blank? }
.........
end
Form:
<%= form_for #project, url: create_project_path(ti: #title), html: { :multipart => true, :class=> "form-horizontal", id: "basicForm" }do |f| %>
<%= f.fields_for :participants do |ff|%>
<%= ff.hidden_field :email, :value => current_user.email %>
<%= ff.hidden_field :title, :value => 'Organizer' %>
<%= ff.hidden_field :status, :value => 'accepted' %>
<% end %>
<%= f.text_field :title, :placeholder => 'Your Project Title'%>
<%= f.text_field :starts, :placeholder => 'mm/dd/yyyy'%>
<%= f.submit ' SAVE PROJECT' %>
<% end %>
UPDATE:
I added #project.participants.build as Samo suggested (and I've updated my code above), which makes the fields_for visible...but my project doesn't save...it redirects back to new_project_path.
I believe I see the issue. In your new_project action, try this:
def new_project
#title = params[:ti]
#project = Project.new
#project.participants.build
end
To elaborate: fields_for is not going to render anything if the association is blank/empty. You need to have at least one participant returned by #project.participants in order to see its fields. #project.participants.build will simply insert a new instance of the Participant class into the association.
As you're using Rails 4 in your application, you don't need to call accepts_nested_attributes_for, because you are already calling params.requirein your Controller.
After #participant = Participant.new you didn't call Participant.saveaction. You do call a #project.save inside your if condition and you should do that for your #participant too. You can call #project.save before redirecting to project_path. I'm not sure if that is a correct approach, but you can try if it works. :-)
I have a model (User) that has_many of another model (Profession) - and this is supposed to be represented by one (or multiple) select menu in a form.
I cannot get my head around why the select menu doesn't get rendered? Am I constructing the select helper in the wrong way? Or is something else wrong in the view or the controller? The name attribute of the User is showing up alright in the form.
The models:
class User < ActiveRecord::Base
has_many :occupations, dependent: :destroy
has_many :professions, through: :occupations
accepts_nested_attributes_for :occupations
end
class Profession < ActiveRecord::Base
has_many :occupations, dependent: :destroy
has_many :users, through: :occupations
end
class Occupation < ActiveRecord::Base
belongs_to :user
belongs_to :profession
end
The controller:
def edit
end
def create
#user = User.new(user_params)
if #user.save
redirect_to #user, notice: 'User was successfully created.'
else
render action: 'new'
end
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:name, :email, ocuppations_attributes: [:id, :user_id, :profession_id])
end
The view (compressed):
<%= form_for(#user) do |f| %>
<%= f.text_field :name %>
<%= f.fields_for :occupations do |builder| %>
<%= builder.select :profession_id, Profession.all.collect {|x| [x.title, x.id]} %>
<% end %>
<% end %>
Shouldn't that be a collection select?
<%= builder.collection_select(:profession_id, Profession.all, :id, :title) %>
I posted an earlier question about this and was advised to read lots of relevant info. I have read it and tried implementing about 30 different solutions. None of which have worked for me.
Here's what I've got.
I have a Miniatures model.
I have a Manufacturers model.
Miniatures have many manufacturers THROUGH a Productions model.
The associations seem to be set up correctly as I can show them in my views and create them via the console. Where I have a problem is in letting the Miniatures NEW and EDIT views create and update to the Productions table.
In the console the command #miniature.productions.create(manufacturer_id: 1) works, which leads me to believe I should be able to do the same in a form.
I THINK my problem is always in the Miniatures Controller and specifically the CREATE function. I have tried out a ton of other peoples solutions there and none have done the trick. It is also possible that my field_for stuff in my form is wrong but that seems less fiddly.
I've been stuck on this for days and while there are other things I could work on, if this association isn't possible then I'd need to rethink my entire application.
The form now creates a line in the Productions table but doesn't include the all important manufacturer_id.
Any help VERY much appreciated.
My New Miniature form
<% provide(:title, 'Add miniature') %>
<h1>Add a miniature</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#miniature) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.fields_for :production do |production_fields| %>
<%= production_fields.label :manufacturer_id, "Manufacturer" %>
<%= production_fields.select :manufacturer_id, options_from_collection_for_select(Manufacturer.all, :id, :name) %>
<% end %>
<%= f.label :release_date %>
<%= f.date_select :release_date, :start_year => Date.current.year, :end_year => 1970, :include_blank => true %>
<%= f.submit "Add miniature", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
Miniatures controller
class MiniaturesController < ApplicationController
before_action :signed_in_user, only: [:new, :create, :edit, :update]
before_action :admin_user, only: :destroy
def productions
#production = #miniature.productions
end
def show
#miniature = Miniature.find(params[:id])
end
def new
#miniature = Miniature.new
end
def edit
#miniature = Miniature.find(params[:id])
end
def update
#miniature = Miniature.find(params[:id])
if #miniature.update_attributes(miniature_params)
flash[:success] = "Miniature updated"
redirect_to #miniature
else
render 'edit'
end
end
def index
#miniatures = Miniature.paginate(page: params[:page])
end
def create
#miniature = Miniature.new(miniature_params)
if #miniature.save
#production = #miniature.productions.create
redirect_to #miniature
else
render 'new'
end
end
def destroy
Miniature.find(params[:id]).destroy
flash[:success] = "Miniature destroyed."
redirect_to miniatures_url
end
private
def miniature_params
params.require(:miniature).permit(:name, :release_date, :material, :scale, :production, :production_attributes)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
def signed_in_user
unless signed_in?
store_location
redirect_to signin_url, notice: "Please sign in."
end
end
end
Miniature model
class Miniature < ActiveRecord::Base
has_many :productions, dependent: :destroy
has_many :manufacturers, :through => :productions
accepts_nested_attributes_for :productions
validates :name, presence: true, length: { maximum: 50 }
validates :material, presence: true
validates :scale, presence: true
validates_date :release_date, :allow_blank => true
def name=(s)
super s.titleize
end
end
Production model
class Production < ActiveRecord::Base
belongs_to :miniature
belongs_to :manufacturer
end
Manufacturer model
class Manufacturer < ActiveRecord::Base
has_many :productions
has_many :miniatures, :through => :productions
validates :name, presence: true, length: { maximum: 50 }
accepts_nested_attributes_for :productions
end
Instead of calling:
#production = #miniature.productions.create
Try Rails' "build" method:
def new
#miniature = Miniature.new(miniature_params)
#miniature.productions.build
end
def create
#miniature = Miniature.new(miniature_params)
if #miniature.save
redirect_to #miniature
else
render 'new'
end
end
Using the build method uses ActiveRecord's Autosave Association functionality.
See http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html
You also need to update your params method, e.g.
def miniature_params
params.require(:miniature).permit(:name, :release_date, :material, :scale, productions_attributes: [:manufacturer_id])
end
Also your fields_for should be plural (I think)...
<%= f.fields_for :productions do |production_fields| %>
for now i've got followings:
model => User (name, email)
has_and_belongs_to_many :trips
model => Trip (dest1, dest2)
has_and_belongs_to_many :users
validates :dest1, :dest2, :presence => true
model => TripsUsers (user_id, trip_id) (id => false)
belongs_to :user
belongs_to :trip
As you see from the code, trip model has validation on dest1, and dest2, but it's not showing up an errors. Controller and view defined as follow:
trips_controller.rb
def new
#user = User.find(params[:user_id])
#trip = #user.trips.build
end
def create
#user = User.find(params[:user_id])
#trip = Trip.new(params[:trip])
if #trip.save
#trip.users << #user
redirect_to user_trips_path, notice: "Success"
else
render :new
end
end
_form.html.erb
<%= simple_form_for [#user, #trip] do |f| %>
<%= f.error_notification %>
<%= f.input :dest1 %>
<%= f.input :dest2 %>
<%= f.submit "Submit" %>
<% end %>
According to the rails guide on presence validation, it can't be used with associated objects. Try to use a custom validation:
validate :destinations_presence
def destinations_presence
if dest1.nil?
errors.add(:dest1, "missing dest1")
elsif dest2.nil?
errors.add(:dest1, "missing dest2")
end
end
I'm trying to get a simple nested form working for a has_many belong_to polymorphic association. The form is rendering the fields but when it submits it giives an 'unknown attribute' error from the create method. Here is the relevant code:
user.rb
class User < ActiveRecord::Base
has_many :images, :as => :imageable
accepts_nested_attributes_for :images
end
users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
#user = User.new
#user.images.build
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to #user
else
render 'new'
end
end
end
views/users/new.html.erb
<%= form_for #user, :html => { :multipart => true } do |form| %>
<%= form.fields_for :images, #user.images do |builder| %>
<%= builder.file_field :images %>
<% end %>
<%= form.submit "Create user" %>
<% end %>
image.rb
class Image < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
has_attached_file :image_resource
end
I am using the paperclip gem for the has_attached_file method in image.rb. The exact error is "unknown attribute: images"
Whoops the only issue here is that I should have it be <%= builder.file_field :image_resource %>