So i want to save a HABTM relationship but i have extra field on my model so i'm usign has_many and through method.
Here's my models:
#project_task.rb
class ProjectTask < ActiveRecord::Base
attr_accessible :description, :name, :user_id, :project_id, :user_ids
belongs_to :project
belongs_to :user #Created by
has_many :project_task_users #Here is the HABTM
has_many :users, :through => :project_task_users #AND HERE
validates :name, :presence => true
validates :project_task_users, :length => { :minimum => 1} #must have atleast 1 record in the HABTM relation
accepts_nested_attributes_for :project_task_users
end
#project_task_user.rb
class ProjectTaskUser < ActiveRecord::Base
belongs_to :user
belongs_to :project_task
end
My form:
<p>Users:</p>
<% for user in #users %>
<div>
<%= check_box_tag "project_task[user_ids][]", user.id, #task.users.include?(user) %>
<%= user.name %> - <%= user.company.name %>
</div>
<% end %>
My controller:
GET
def new_task
#project = Project.find(params[:project_id])
#task = ProjectTask.new(:project_id => #project.id)
#users = #project.users
end
POST
def new_task_post
#project = Project.find(params[:project_id])
#task = ProjectTask.new params[:project_task]
#task.user_id = current_user.id
if #task.save
redirect_to #project
else
#users = #project.users
render action:"new_task"
end
end
When i submit, the #task.save returns false and the errors array with the project_task_users validation
Update
as Pablo89 pointed out i renamed my check_box_tag to this
<%= check_box_tag :user_ids, user.id, #task.users.include?(user), :name => 'project_task[user_ids][]' -%>
and it saves only if i comment out the validation. How should i validate that a user is selected while creating a project_task?
Related
I am using Rails 5.1 and im having some issues saving params on an n:n relationship.
I have three models:
class Course < ApplicationRecord
belongs_to :studio
has_many :reviews, dependent: :destroy
has_many :has_category
has_many :categories, through: :has_category
validates :name, presence: true
end
class Category < ApplicationRecord
has_many :has_category
has_many :courses, through: :has_category
end
class HasCategory < ApplicationRecord
belongs_to :category
belongs_to :course
end
and a simple form to create a new course with different categories using check_box_tag (not sure if using it correctly though)
<%= simple_form_for [#studio, #course] do |f| %>
<%= f.input :name %>
<%= f.input :description %>
<% #categories.each do |category| %>
<%= check_box_tag "course[category_ids][]", category.id, true %>
<%= category.name%>
<% end %>
<%= f.button :submit %>
<% end %>
And all is permitted and created on the courses controller:
def new
#studio = Studio.find(params[:studio_id])
#course = Course.new
#course.studio = #studio
#categories = Category.all
end
def create
#studio = Studio.find(params[:studio_id])
#course = Course.new(course_params)
#course.studio = #studio
#categories = params[:category_ids]
if #course.save
redirect_to course_path(#course)
else
render :new
end
end
def course_params
params.require(:course).permit(:studio_id, :name, :description, :category_ids)
end
With better_errors i know the categories are being requested, here the request info:
"course"=>{"name"=>"Course test", "description"=>"testing", "category_ids"=>["2", "3"]}, "commit"=>"Create Course", "controller"=>"courses", "action"=>"create", "studio_id"=>"16"}
but the categories are not saved on course_params, HasCategory instance or on the Course, i´ve tried with #course.categories = params[:category_ids] and other solutions without success.
How do i save the categories to the courses?
Try the following
Change the strong parameter with category_ids: []
def course_params
params.require(:course).permit(:studio_id, :name, :description, category_ids: [])
end
Comment out this line #categories = params[:category_ids]
Hope it helps
I have three model classes related to each other.
class Student < ActiveRecord::Base
has_many :marks
belongs_to :group
accepts_nested_attributes_for :marks,
reject_if: proc { |attributes| attributes['rate'].blank?},
allow_destroy: true
end
This class describes a student that has many marks and I want to create a Student record along with his marks.
class Mark < ActiveRecord::Base
belongs_to :student, dependent: :destroy
belongs_to :subject
end
Marks are related both to the Subject and a Student.
class Subject < ActiveRecord::Base
belongs_to :group
has_many :marks
end
When I try to create the nested fields of marks in loop labeling them with subject names and passing into in it's subject_id via a loop a problem comes up - only the last nested field of marks is saved correctly, whilst other fields are ignored. Here's my form view code:
<%= form_for([#group, #student]) do |f| %>
<%= f.text_field :student_name %>
<%=f.label 'Student`s name'%><br>
<%= f.text_field :student_surname %>
<%=f.label 'Student`s surname'%><br>
<%=f.check_box :is_payer%>
<%=f.label 'Payer'%>
<%= f.fields_for :marks, #student.marks do |ff|%>
<%#group.subjects.each do |subject| %><br>
<%=ff.label subject.subject_full_name%><br>
<%=ff.text_field :rate %>
<%=ff.hidden_field :subject_id, :value => subject.id%><br>
<%end%>
<% end %>
<%= f.submit 'Add student'%>
<% end %>
Here`s my controller code:
class StudentsController<ApplicationController
before_action :authenticate_admin!
def new
#student = Student.new
#student.marks.build
#group = Group.find(params[:group_id])
#group.student_sort
end
def create
#group = Group.find(params[:group_id])
#student = #group.students.new(student_params)
if #student.save
redirect_to new_group_student_path
flash[:notice] = 'Студента успішно додано!'
else
redirect_to new_group_student_path
flash[:alert] = 'При створенні були деякі помилки!'
end
end
private
def student_params
params.require(:student).permit(:student_name, :student_surname, :is_payer, marks_attributes: [:id, :rate, :subject_id, :_destroy])
end
end
How can I fix it?
#student.marks.build
This line will reserve an object Mark.
If you want multi marks, May be you need something like this in new action :
#group.subjects.each do |subject|
#student.marks.build(:subject=> subject)
end
Hope useful for you.
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.
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) %>
Hi I'm currently working on my first rails project, a site for users to make albums and upload pics. I have the registration, logging in, and friending installed into my app. I'm trying to make it so that in the album creation form, you can see a list of your friends and select who you want to share access to the album with (meaning whoever you select would also be part of #album.users. I'm planning on using a checkbox (I can't think of any better way) to make this selection. However, I am not sure how to link the friendship model with the album/new form. This is how my form looks like:
album/new.html.erb
<%= form_for ([#user, #album]), :html => { :id => "uploadform", :multipart => true } do |f| %>
<div class="formholder">
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.check_box :friends %>
<%= f.label :description %>
<%= f.text_area :description %>
<br>
<%=f.submit %>
</div>
<% end %>
an error occurs on line #6 (
<%= f.check_box :friends %>
the error:
undefined method 'friends' for #<Album:0x007fa3a4a8abc0>
I can understand why, but I don't know how to fix it. I have the typical friendship join model to add friends, and I want to be able to see a list of all the friends and select them. I think a following step would be to add something like #album.users << #user.friendships.find_by_name(params[:friends]) in the create action in the albums controller, but I don't know how I would loop through the form that only returns one param for friends?
Here are my files:
Albums controller create action:
def create
#user = User.find(params[:user_id])
#album = #user.albums.build(params[:album])
# not so sure about the following line.
#album.users << #user.friendships.find_by_name(params[:friends])
respond_to do |format|
if #user.save
format.html { redirect_to user_album_path(#user, #album), notice: 'Album was successfully created.' }
format.json { render json: #album, status: :created, location: #album}
else
format.html { render action: "new" }
format.json { render json: #album.errors, status: :unprocessable_entity }
end
end
end
album model
class Album < ActiveRecord::Base
attr_accessible :name, :description
validates_presence_of :name
has_many :album_users
has_many :users, :through => :album_user
has_many :photos
end
user model
class User < ActiveRecord::Base
has_secure_password
attr_accessible :email, :name, :password, :password_confirmation
validates_presence_of :password, :on => :create
validates_format_of :name, :with => /[A-Za-z]+/, :on => :create
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
validates_length_of :password, :minimum => 5, :on => :create
has_many :album_users
has_many :albums, :through => :album_users
accepts_nested_attributes_for :albums
has_many :friendships
has_many :friends, :through => :friendships
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
album_user model (join table to make many-to-many relationship between album, which has many users, and users, which has many albums)
class AlbumUser < ActiveRecord::Base
belongs_to :album
belongs_to :user
end
friendship model
class Friendship < ActiveRecord::Base
attr_accessible :friend_id
belongs_to :user
belongs_to :friend, :class_name => "User"
end
let me know if you need any more info!! Thanks in advance!!!
You should add users_ids (yes, two "s") to the list of accessible attributes of Album, and then use a "select multiple" on the :users_ids field.
<%= f.collection_select(:users_ids, User.all, :id, :name, :multiple => true) %>