I am new to Rails and I have these checkboxes that display the options just fine, but aren't changing anything in the database as the form is submitted.
The form in views has the following piece of code:
<%= form_for(#sector) do |f| %>
<%= f.collection_check_boxes :admins_id, Admin.all, :id, :name %>
<% end %>
and this is the corresponding action in the sectors controller:
def update
#sector = Sector.find(params[:id])
#sector.admins_id = params[:admins_id]
respond_to do |format|
if #sector.update(sector_params)
format.html { redirect_to #sector, notice: 'Sector was successfully updated.' }
format.json { render :show, status: :ok, location: #sector }
else
format.html { render :edit }
format.json { render json: #sector.errors, status: :unprocessable_entity }
end
end
end
private
def sector_params
params.require(:sector).permit(:title, :admins_id)
end
And, finally, I have these relations in the models:
class Sector < ActiveRecord::Base
has_many :admins, dependent: :destroy
validates :title, presence: true
validates :title, uniqueness: true
end
class Admin < ActiveRecord::Base
belongs_to :sector
end
Also, I can create and assign admins just fine in the rails console.
If you are setting a single admins_id then you don't need check boxes (which will pass through an array of ids) use collection_radio_buttons (for a single id) instead.
However, if you want to set multiple admins through the has_many association, then keep the checkboxes, but change the attribute name to be admin_ids. (Don't forget to change the name in the permit() whitelist as well).
Also, you can remove this line:
#sector.admins_id = params[:admins_id]
It's not necessary because it is set through the update().
Related
I'm having trouble doing a has_and_belongs_to_many, my data is structured as follows
# app/models/student.rb
class Student < ApplicationRecord
belongs_to :city
belongs_to :degree
has_and_belongs_to_many :services, optional: true
end
# app/models/service.rb
class Service < ApplicationRecord
has_and_belongs_to_many :student, optional: true
belongs_to :vendor
belongs_to :degree, optional: true
end
in my database schema i have this table and the tables of student and service.
create_table "services_students", id: false, force: :cascade do |t|
t.integer "service_id", null: false
t.integer "student_id", null: false
end
what happens is for a Student to be associated with a Service, I needed to add some lines in services_controller.create()
# POST /services or /services.json
def create
#service = Service.new(service_params)
for student in params[:service][:student]
if student != ""
#service.student << Student.find(student)
end
end
respond_to do |format|
if #service.save
format.html { redirect_to service_url(#service), notice: "Service was successfully created." }
format.json { render :show, status: :created, location: #service }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #service.errors, status: :unprocessable_entity }
end
end
end
this way the tables save the information correctly. however, in the update() function, when saving the record, the service_students table records are duplicated instead of being updated.
in services_controller i have set the permit params as this:
# service_controller.rb
# Only allow a list of trusted parameters through.
def service_params
params.require(:service).permit(:student, :vendor_id, :degree_id, :category, :description)
end
and in my form is like this:
# .... begin of form ...
<%= form.label :student, "Aluno(s)" %>
<%= form.collection_check_boxes :student, Student.all, :id, :name do |b|
b.label(class:"w-full ") { b.check_box(class:"rounded", checked: #service.student.ids.include?(b.object.id)) + b.text }
# .... more fields of form ....
I'm not understanding what I'm doing wrong. shouldn't the update function, and even create(), handle this without having to add more code?
I tried to follow some tutorials on the internet, and I realized that the activeRecord should generate the attribute students_ids or students to register the association correctly, but I didn't understand exactly why this happens or why in my model it is referred to as student. (maybe something is wrong)
>> rails console
service = Service.find(1) # get the Service with id: 1
student1 = Student.find(1) # get the Student with id: 1
student2 = Student.find(2) # get the Student with id: 2
service.students << student1 # error
service.student << student1 # works
service.students #error #method missing
service.student # display all students relationship
is this supposed to happen?
The assocation should have a plural name:
class Service < ApplicationRecord
has_and_belongs_to_many :students # this should be plural!
belongs_to :vendor
belongs_to :degree, optional: true
end
Use the students_ids method generated by has_and_belongs_to_many :students with your input:
<%= form.collection_check_boxes :student_ids, Student.all, :id, :name do |b| %>
<%= b.label(class:"w-full") { b.check_box(class:"rounded") + b.text } %>
<% end %>
And you need to whitelist an array of ids:
def service_params
params.require(:service)
.permit(
:vendor_id, :degree_id,
:category, :description,
student_ids: [] # permits an array of values
)
end
And just get rid of the cruft:
def create
#service = Service.new(service_params)
respond_to do |format|
if #service.save
format.html { redirect_to #service, notice: "Service was successfully created." }
format.json { render :show, status: :created, location: #service }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #service.errors, status: :unprocessable_entity }
end
end
end
The students_ids= method which is also created by has_and_belongs_to_many :students will automatically add/delete the rows in the join table.
This is a web app for scheduling our company's various site deployments among the developers and product owners on our Scrum team, when we launch updates or improvements. I have two models, User and Release. A Release is a single deployment event. Then I have a join table, called release_users. A user has and belongs to many releases. A release has many users, under the name product_owners, and belongs to one user, under the name developer. The Release table has a developer_id column which equals the User's ID, so it doesn't involve the ReleaseUser association at all (at least, that's what I want).
Here's the problem: when I create a new Release record (through the form), it automatically creates/saves a ReleaseUser record for the developer in addition to the product owners. When I look at #release.product_owners, I see the developer listed under there when it shouldn't be. It should only create ReleaseUser records for product owners. #release.developer works as expected, it selects the user from the User table based on developer_id and doesn't go through the ReleaseUser table.
So something is wrong in my model configurations I think? Rails is performing some behind-the-scenes magic that I can't pinpoint.
Code
release.rb:
class Release < ActiveRecord::Base
has_many :release_users, dependent: :destroy
has_many :product_owners, :through => :release_users, :source => :user
belongs_to :developer, :class_name => "User"
end
user.rb:
class User < ActiveRecord::Base
has_many :release_users, dependent: :destroy
has_many :releases, :through => :release_users
end
release_user.rb:
class ReleaseUser < ActiveRecord::Base
belongs_to :release
belongs_to :user
end
_form.html.erb:
<div class="field">
<%= f.label "Developer" %><br>
<%= f.select :developer_id, options_for_select(User.select_options, selected: #release.selected_option), { include_blank: 'None' } %>
</div>
<div class="field">
<%= f.label "Product Owners" %><br>
<%= f.collection_check_boxes :product_owner_ids, User.all, :id, :full_name do |b| %>
<label class="checkbox">
<%= b.check_box %> <%= b.label %> <br/>
</label>
<% end %>
</div>
releases_controller.rb:
# POST /releases
# POST /releases.json
def create
#release = Release.new(release_params)
# Release belongs to one developer at most
unless release_params[:developer_id].empty?
#developer = User.find(release_params[:developer_id])
# User has many releases, add to array
#developer.releases << #release
#developer.save
end
respond_to do |format|
if #release.save
format.html { redirect_to releases_url, notice: 'Release was successfully created.' }
format.json { render :show, status: :created, location: #release }
else
format.html { render :new }
format.json { render json: #release.errors, status: :unprocessable_entity }
end
end
end
(Rails 4)
This line:
#developer.releases << #release
is adding a record to ReleaseUsers because you stated that:
class User
has_many :releases, :through => :release_users
end
So by using #developer.releases << #release you are telling rails to create that association in the release_users table.
It seems you need to isolate the scope for something like developer_releases on User and then none of the unless block is needed.
Something like
class User
# existing relationships
has_many :developer_releases, class_name: 'Release', foreign_key: :developer_id
end
Then the controller code can be slimmed down:
def create
#release = Release.new(release_params)
respond_to do |format|
if #release.save
format.html { redirect_to releases_url, notice: 'Release was successfully created.' }
format.json { render :show, status: :created, location: #release }
else
format.html { render :new }
format.json { render json: #release.errors, status: :unprocessable_entity }
end
end
end
this is creating the join table
#developer.releases << #release
There's no reason to do that. Just take it out.
i use rails 5 , simple form. in my app there is a Category model and there is a OnlineProduct model. i dont know why when i want to add some categories to my OnlineProduct association table remain empty and don't change.
Category model:
class Category < ApplicationRecord
has_ancestry
has_and_belongs_to_many :internet_products
end
InternetProduct model:
class InternetProduct < ApplicationRecord
belongs_to :user
belongs_to :business
has_and_belongs_to_many :categories
end
InternetProduct controller:
def new
#internet_product = InternetProduct.new
end
def create
#internet_product = InternetProduct.new(internet_product_params)
respond_to do |format|
if #internet_product.save
format.html { redirect_to #internet_product, notice: 'Internet product was successfully created.' }
format.json { render :show, status: :created, location: #internet_product }
else
format.html { render :new }
format.json { render json: #internet_product.errors, status: :unprocessable_entity }
end
end
end
private:
def internet_product_params
params.require(:internet_product).permit(:name, :description, :mainpic, :terms_of_use,
:real_price, :price_discount, :percent_discount,
:start_date, :expire_date, :couponـlimitation, :slung,
:title, :meta_data, :meta_keyword, :enability, :status,
:like, :free_delivery, :garanty, :waranty, :money_back,
:user_id, :business_id,
categoriesـattributes: [:id, :title])
end
and in the view only the part of who relate to categories :
<%= f.association :categories %>
all the categories list in view (form) but when i select some of them not save in database. in rails console i do this
p = InternetProduct.find(5)
p.categories = Category.find(1,2,3)
this save to database without any problem, what should i do ?
tanks for reading this
I found solution to solve this. when we use has_and_belong_to_many or any other relation , if you want to use collection select in simple_form , in the model also should be add this command for nesting form
accepts_nested_attributes_for :categories
also in the controller in related method for example in the new we should
def new
#internet_product = InternetProduct.new
#internet_product.categories.build
end
Here are my models:
class Examination < ActiveRecord::Base
has_many :categorizations
has_many :exam_statuses, :through => :categorizations
end
class Categorization < ActiveRecord::Base
belongs_to :examination
belongs_to :exam_status
end
class ExamStatus < ActiveRecord::Base
has_many :categorizations
has_many :examinations, :through => :categorizations
end
I can assign relations from the console without any problem by typing;
e = Examination.first
e.exam_status_ids = [1,2]
And also in the examinations/index.html.erb file I can list exam_statuses without any problem.
The problem is, I can't update or create any exam_status relations from examinations/_form.html.erb file!
I'm trying to make this with simple_form:
<%= f.association :exam_statuses, as: :check_boxes, label: 'Sınavın Durumu' %>
Its listing all the statuses with checkboxes but not updating them.
Logs saying:
"Unpermitted parameters: exam_status_ids"
And finally my controller, which is generated by "scaffold" by default, for update is:
def update
respond_to do |format|
if #examination.update(examination_params)
format.html { redirect_to #examination, notice: 'Examination was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #examination.errors, status: :unprocessable_entity }
end
end
end
From what your logs say, you should permit the parameter, in the controller:
def examination_params
params.require(:examination).permit(:exam_status_ids)
end
Don't forget to add other parameters in the permit call!
Then you can use it in your controller's action:
def update
...
#examination.update_attributes! examination_params
...
end
I think you need to use accepts_nested_attributes in this case to get it updated.
For more details you can refer this article
I have one model, User, and then 2 other models: Editor and Administrator associated with the user model via a polymorphic association, so I want to have 2 type of users, and they will have different fields, but I need them to share certain features (like sending messages between both).
I thus need to keep the user ids in one table, users, and the other data in other tables, but I want that when a user signs up they first create the account and then the profile according to the type of profile they did pick.
model/user.rb
class User < ActiveRecord::Base
belongs_to :profilable, :polymorphic => true
end
model/administrator.rb
class Administrator < ActiveRecord::Base
has_one :user, :as => :profilable
end
model/Editor.rb
class Editor < ActiveRecord::Base
attr_accessor :iduser
has_one :user, :as => :profilable
end
controllers/user.rb
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
if params[:tipo] == "editor"
format.html {redirect_to new_editor_path(:iduser => #user.id)}
else
format.html { redirect_to new_administrator_path(#user) }
end
# format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
controllers/editor.rb
def new
#editor = Editor.new
#editor.iduser = params[:iduser]
respond_to do |format|
format.html # new.html.erb
format.json { render json: #editor }
end
end
def create
id = params[:iduser]
#user = User.find(id)
#editor = Editor.new(params[:editor])
#editor.user = #user
respond_to do |format|
if #editor.save
format.html { redirect_to #editor, notice: 'Editor was successfully created.' }
format.json { render json: #editor, status: :created, location: #editor }
else
format.html { render action: "new" }
format.json { render json: #editor.errors, status: :unprocessable_entity }
end
end
end
views/editor/_form.html.erb
<div class="field">
<%= f.label :bio %><br />
<%= f.text_area :bio %>
<%= f.hidden_field :iduser%>
</div>
routes.rb
Orbit::Application.routes.draw do
resources :administrators
resources :editors
resources :users
When someone creates a new user they have to pic "Editor" or "Administrator" with a radio button, then using that parameter, the code will create an Editor or Administrator profile.
I am not sure if i have the association right, because it should be "User has a profile (editor/administrator)" but in this case is "Profile (administrator/editor) has a user".
The question:
Is the association right for what I want to accomplish?
How could I pass the user to the new editor method?
The way i have it right now is not working, and as I said, the association doesn't seem to be right.
Thanks for the time
Try and swap the association,
The user will have an administrator profile, and administrator profile will belong_to the user.
Administrator(:user_id, :other_attributes)
Editor(:user_id, :other_attributes)
So that,
class Administrator < ActiveRecord::Base
belongs_to :user
end
class Editor < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_one :administrator
has_one :editor
end