I am unsure why my cocoon nested form is not appearing and any help would be much appreciated
the <button><%= link_to_add_association 'add a required skill', f, :requiredskills %></button> works perfectly well in displaying a form
but i am unsure why this is not rendering the form <%= render 'requiredskill_fields', :f => duty %>
what i would like to do is to have a form already displayed and when a user clicks add a required skill another form is displayed.
At present when a user clicks add a required skill that displays
another form - the main issue is having a form to be displayed
initially. I am assuming this <%= render 'requiredskill_fields', :f
=> duty %> is suppose to put a form in place but i am unsure why it is not working
user/_form.html.erb
<%= simple_form_for(#user) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :firstname %>
<%= f.input :lastname %>
<h3>required skills & expertise</h3>
<div>
<div class="requiredskill_info" id="skill">
<%= f.simple_fields_for :requiredskills do |skill| %>
<%= render 'requiredskill_fields', :f => skill %>
<% end %>
<div class="add_requiredskill"><button><%= link_to_add_association 'add a required skill', f, :requiredskills %></button></div>
</div>
</div>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
user/_requiredskill_fields.html.erb
<div class="nested-fields">
<%= f.association :category_advert, collection: CategoryAdvert.all, prompt: "select a category" %>
<%= f.grouped_collection_select :category_advertskill_id, CategoryAdvert.order(:name), :category_advertskills, :name, :id, :name, {prompt: "Select a category"}, {class: "category_advertskill"} %>
<button><%= link_to_remove_association 'remove required skill', f %></button>
</div>
users_controller.rb
class UsersController < ApplicationController
respond_to :html, :xml, :json
before_action :set_user, only: [:show, :edit, :update, :destroy]
def index
#users = User.all
#user = current_user
end
def show
#resume = #user.resume
end
def edit
end
def update
#user.update(user_params)
redirect_to #user
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:email, :firstname, :lastname, :city, :category_qualification_id, :category_careerlevel_id, :desiredjob, :category_distance_id, :preferedlocation, :category_notice_id, :category_country_id, :category_positiontype_id, :image, :cvattachment, :hidecv, :jobadvice, :validlicense, :owntransport, :considerrelocation, :preferredlocation, :neednotice, :stratdate, :availabletowork, :category_outsource_id, :category_advertskill_id, :category_age_id, languages_attributes: [:id, :name, :_destroy], requiredskills_attributes: [:id, :name, :category_advert_id, :category_advertskill_id, :category_year_id, :category_level_id, :_destroy])
end
end
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :requiredskills
has_many :category_advertskills, through: :requiredskills
has_many :category_adverts, through: :requiredskills
has_one :resume
accepts_nested_attributes_for :languages, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :requiredskills, :reject_if => :all_blank, :allow_destroy => true
end
def edit
#requiredskills = #user.requiredskills.present? ? #user.requiredskills : #user.requiredskills.build
end
change this code in controller
Related
Im new to ruby on rails so i need some tips please.
Im trying to render some checkboxes on the edit view for a user.
I have tried to follow the documentation for the nested_attributes but the checkboes does not render.
Here is the relation between the two models:
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :softwares
has_many :courses
accepts_nested_attributes_for :softwares
accepts_nested_attributes_for :courses
The Edit view for a user
<div class="container">
<div class="row">
<div class="col-md-12 mt-5">
<%= form_for #student, url: auth_student_path(#student), method: :put do |f| %>
<div class="col-md-12 mb-5 mt-5">
<div class="row">
<h3 class="mb-3 filter_heading">Softwares</h3>
<% #softwares.each do |sf|%>
<%= f.fields_for :softwares do |software| %>
<div class="col-md-3">
<div class="courses">
<%= software.label sf.title %>
<%= software.check_box :title, {multiple: true}, sf.title, nil %>
</div>
<% sf.courses.each do |crs|%>
<%= f.fields_for :courses do |course|%>
<div class="mt-1 courses-checkbox">
<%= course.label crs.name %>
<%= course.check_box :name, {multiple: true}, crs.name , nil %>
</div>
<% end %>
<% end%>
</div>
<% end %>
<% end%>
</div>
<div class="form-group">
<%= f.submit "Save", class:"btn btn-primary"%>
</div>
<% end %>
</div>
</div>
</div>
The Controller
module Auth
class StudentsController < ApplicationController
before_action :authenticate_user!
before_action :set_student, only: %i[delete_certificates]
def edit
authorize! :edit, #user
#softwares = Software.all
#student = User.find(params[:id])
end
def update
authorize! :update, #user
#student = User.find(params[:id])
if #student.update(student_params)
redirect_to edit_auth_student_path(#student)
else
redirect_to edit_auth_student_path(#student)
end
end
def show
def set_student
#student = User.find(params[:student_id])
end
private
def student_params
params.require(:user).permit(
:email,
:firstname,
:lastname,
:phone,
:locked,
:approved,
:role,
badges: [],
certificates: [],
softwares_attributes: [:title],
courses_attributes: [:name],
)
end
end
end
Please help me.
You don't need accepts_nested_attributes_for just to select existing records and associate them with something. Its only needed if you need to create/update the other record (the course or software) at the same time.
I'm also guessing you don't actually want to have a one-to-many assocation and duplicate every course and every software for each user - instead you want a many to many assocation and some data normalization.
So create a join table to hold the assocation between users and courses for example:
class User < ApplicationRecord
has_many :enrollments, foreign_key: :student_id
has_many :courses, through: :enrollments
end
# rails g model enrollment student:belongs_to course:belongs_to
class Enrollment < ApplicationRecord
belongs_to :student, class_name: 'User'
belongs_to :course
end
class Course < ApplicationRecord
has_many :enrollments
has_many :students, through: :enrollments
end
And then you just create inputs that use the course_ids / course_ids= setter and getter created by has_many :courses, through: :enrollments.
<%= form_with(model: #student, url: auth_student_path(#student), method: :put) do |f| %>
<div class="field">
<%= f.label :course_ids, 'Select your courses' %>
<%= f.collection_select :course_ids, #courses, :id, :name, multiple: true %>
</div>
# ...
<% end %>
And then you just whitelist an array of ids in your controller:
params.require(:user)
.permit(
# ...
course_ids: []
)
In fact if your ever passing existing records as anything but an ID you're doing it very wrong.
There are still plenty of issues with this code but this should at least be nudge in the correct direction.
I have the following models in my application:
User:
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
before_destroy { roles.clear }
has_many :users_roles
has_many :roles, through: :users_roles
accepts_nested_attributes_for :roles
#accepts_nested_attributes_for :user_extras
#id :confirmable is activated
def confirmation_required?
false
end
end
Role:
class Role < ApplicationRecord
#before_destroy { users.clear }
has_many :users, through: :users_roles
end
and UserRoles:
class UsersRoles < ApplicationRecord
belongs_to :user
belongs_to :role
end
I also have a form that will accept nested attributes, which looks something like this:
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<%= f.fields_for :roles do |field| %>
<%= field.label :name %></div>
<%= field.text_field :name %>
<% end %>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
Also I have a controller that renders this form:
class Admin::AccountController < ApplicationController
before_action :authenticate_user!
layout "admin/layouts/dashboard"
def index
#resource = User.new
#resource2 = Role.new
#resource.roles << #resource2
p "==================="
p #resource
p #resource2
p "==================="
#resource.roles.build
# respond_to do |format|
# format.html
# format.json { render json: #resource }
# end
end
private
def admin_account_params
params.require(:resource).permit(:email, :password, :password_confirmation, roles_attributes: [ :name ])
end
end
The thing is when I visit the page, I get the following error:
uninitialized constant User::UsersRole
Extracted source (around line #9):
7
8
9
10
11
12
#resource = User.new
#resource2 = Role.new
#resource.roles << #resource2
p "==================="
I am not sure what is wrong with this at the moment. It will be great if you can spot the problem. Many thanks in advance.
Model classes by convention should be singular so the model class name should be...
class UsersRole < ApplicationRecord
belongs_to :user
belongs_to :role
end
This will automatically map to a database table named users_roles
If you insist on using a plural class name then you need to specify the class name explicitly
has_many :users_roles, class_name: 'UsersRoles'
And you'll need this in both the User model and the Role model
I am using cocoon in my Rails app for assigning employees (users) to projects (many to many connection). The creation of associations is working correctly, but each time I add another employee cocoon adds an empty form field in the edit view. None of the other cocoon form fields in the edit view are populated either. Could this be due to the usage of dropdowns (select)?
When I inspect the form in my browser I can see that each field seems to be assigned to one of the associations, but the selection is still empty.
What I would like to achieve is, that every association is displayed in a cocoon form field, so that they can be edited. Thanks for any help in advance!
My code is below (Sorry for any mess, it is my first time trying out a many to many connection of two models).
Project Edit View
<%= form_for(#project, :url => project_path, method: :patch) do |f| %>
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :customer %>
<%= f.text_field :customer, class: "form-control" %>
</div>
<%= f.fields_for :user_projects do |collab| %>
<% collab.hidden_field :project_id, value: #project.id %>
<%= render 'user_project_fields', f: collab %>
<% end %>
<div class="add-collaborator">
<%= link_to_add_association "add", f, :user_projects, class: "btn btn-mmc" %>
</div>
<div class="actions">
<%= f.submit "Save Changes", class: "btn btn-mmc btn-mmc-medium" %>
</div>
<% end %>
cocoon field partial
<div class="nested-fields">
<%= f.label "Select User" %>
<div class="form-group custom-form-group">
<%= f.select(:user_id, options_for_select(User.all.map { |u| [u.email, u.id] }), {include_blank: true}, {class: 'form-control'})%>
<div class="btn-user-project">
<%= link_to_remove_association "x", f, class: "btn btn-mmc-attention btn-mmc" %>
</div>
</div>
</div>
Project Model
class Project < ApplicationRecord
has_many :user_projects
has_many :users, :through => :user_projects
accepts_nested_attributes_for :user_projects, reject_if: :all_blank, allow_destroy: true
end
User Model
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :user_projects
has_many :projects, :through => :user_projects
end
Project Controller
def edit
#project = Project.find(params[:id])
#project.user_projects.build
end
def update
#project = Project.find(params[:id])
#project.update(project_params)
#new_collaborator = UserProject.new(user_id: params[:user_id], project_id: params[:project_id])
#new_collaborator.save
if #project.update(project_params) && #new_collaborator.save
redirect_to projects_path
else
render :edit
end
end
private
def project_params
params.require(:project).permit(:title, :customer, :delted, user_projects_attributes: [:user_id, :project_id]).reject { |_, v| v.blank? }
end
I am guessing the mapping to the actual value is not done correctly, e.g. the value of the user_id is not marked as selected, in the options_for_select you have to add the selected value as parameter (see documentation).
However, there is a much easier version:
<%= f.collection_select(:user_id, User.all, :id, :email) %>
BTW using a gem like simple_form also makes building forms a lot more intuitive and straightforward.
That's because you're create object twice.
First time:
#project.update(project_params) # from accepts_nested_attributes_for
Second time:
#new_collaborator = UserProject.new(user_id: params[:user_id], project_id: params[:project_id])
#new_collaborator.save
P.s.
Can you show project_params method? I think I know why first object empty
I cannot seem to get nested attributes to save to the database, though I can see the params in terminal. I am using Rails 4.2.
Here are my models:
class Device < ActiveRecord::Base
belongs_to :hub
has_many :accessories, dependent: :destroy
accepts_nested_attributes_for :accessories,
reject_if: proc { |attributes| attributes['material'].blank? },
allow_destroy: true
end
class Accessory < ActiveRecord::Base
belongs_to :device
end
Here is the controller. I have my device model nested under user and hub model.
class DevicesController < ApplicationController
def edit
#user = User.find_by(params[:user_id])
#hub = Hub.find_by_title(params[:hub_id])
#device = Device.find_by(id: params[:id])
end
def update
#user = User.find_by(params[:user_id])
#hub = Hub.find_by_title(params[:hub_id])
#device = Device.find_by(id: params[:id])
if #device.update_attributes(device_params)
flash[:success] = "update successfully"
redirect_to user_hub_device_path(#user, #hub, #device)
else
render 'edit'
end
end
private
def device_params
params.require(:device).permit(:model, :hub_id, :resolution, :materials, :startcost, :take_online, :delivery_time, :unitcost, :color, :accessories, :accessories_attributes => [:id, :name, :cost, :color, :device_id, :_destroy])
end
end
Finally is my form.
<%= form_for([#user, #hub, #device]) do |f| %>
<fieldset>
<div id="material">
<%= f.fields_for :accessories do |a| %>
<%= render 'devices/accessory', a: a %>
<% end %>
</div>
</fieldset>
The partial:
<div class="row">
<%= a.collection_select :name, Material.all, :material, :material %>
<%= a.text_field :cost, id: "right-label" %>
<%= a.text_field :color, id: "right-label" %>
<%= a.check_box :_destroy %>
</div>
You are whitelisting params[:device][:materials] but you are checking attributes['material'].blank? (note the the s on the end). Which causes the nested attributes to be rejected.
I am working on my first rails application and I am attempting to add a comment section. The comments will fall under each topic. I am seeing comments that are being generated but I am not able to get it configured so that I can input my own comments. I will list below the changes I have made to my code as instructed by my assignment.
Heres a change to my app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :user
validates :body, length: { minimum: 5 }
validates :body, presence: true
validates :user_id, presence: true
end
Heres my app/models/user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
has_many :posts
has_many :comments
mount_uploader :avatar, AvatarUploader
def admin?
role == 'admin'
end
def moderator?
role == 'moderator'
end
end
I have to also update db/seeds.rb
# Create Comments
100.times do
Comment.create!(
# user: users.sample, # we have not yet associated Users with Comments
post: posts.sample,
user: users.sample,
body: Faker::Lorem.paragraph
)
end
Updated my config/routes.rb
resources :comments, only: [:create]
Updated my app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = current_user.comments.new(comment_params)
#comment.post = #post
#new_comment = Comment.new
authorize #comment
end
end
The final adjustments I made was to app/views/comments/_form.html.erb
<% if current_user %>
<h4>Add a comment:</h4>
<%= form_for [#post, #post.comments.build], remote: true do |f| %>
<%= f.label :body %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
<% end %>
I hope that this is sufficient enough for some type of a response as to what I may be missing. I do not get an error, the box that I am looking for to create a comment just does not appear. Here is an example of what I am trying to accomplish:
http://oi62.tinypic.com/f35h5y.jpg
edit:
Here is the app/views/posts/show.html.erb
<h1><%= markdown #post.title %></h1>
<div class="row">
<div class="col-md-8">
<small>
<%= image_tag(#post.user.avatar.tiny.url) if #post.user.avatar? %>
submitted <%= time_ago_in_words(#post.created_at) %> ago by
<%= #post.user.name %>
</small>
<p><%= markdown #post.body %></p>
<p><%= image_tag(#post.image_url) if #post.image? %></p>
</div>
<div class="col-md-4">
<% if policy(#post).edit? %>
<%= link_to "Edit", edit_topic_post_path(#topic, #post), class: 'btn btn-success' %>
<% end %>
</div>
</div>