I'm trying to bring a list of Users that a "request" has been accepted for a user to select from. I set up the collection and what is showing up on the view page is either the user id when I put :user_id or its shows <User:0x007fbdrf252a60> when i put in user. I tried putting in :name but it returns a "undefined method name" error.
Currently my form looks like:
<%= form_for :event_logs, url: event_logs_path do |f| %>
<%= f.select :user_id, options_from_collection_for_select(#user_event_log, :id, :name ) %>
<%= f.hidden_field :event_id, :value => #event.id %>
<%= f.submit 'Send', class: 'btn btn-success' %>
<% end %>
And in the controller for the show its:
#user_event_log = RequestLog.usr_req_by current_user
The user_req_by in the model is: scope :usr_req_by, ->(user) { where(user_id: user.id) }
If more information is needed I'm more than happy to add it. Thank you
User Model:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
validates_presence_of :name
has_many :request_logs, dependent: :destroy
acts_as_messageable
def first_name
self.name.split.first
end
def last_name
self.name.split.last
end
end
Request Log Model:
class RequestLog < ApplicationRecord
enum status: { accepted: 0, rejected: 1 }
belongs_to :user, optional: true
belongs_to :request, optional: true
validates :user_id, presence: true
validates :request_id, presence: true
scope :usr_req_by, ->(user) { where(user_id: user.id) }
scope :req_itp, ->(requests) { where(request_id: requests) }
end
The collection iterated over, is a collection of RequestLog. So when you use :name in options_from_collection_for_select, it tries to call .name on a RequestLog.
I suppose you want the users name there? If so, you can add a helper method to RequestLog
def user_name
return user.name
end
and use :user_name in the view.
Another option, is to pass an object, that responds to .call as a param, as so:
<%= form_for :event_logs, url: event_logs_path do |f| %>
<%= f.select :user_id, options_from_collection_for_select(#user_event_log, :id, ->(log){ log.user.name }) %>
<%= f.hidden_field :event_id, :value => #event.id %>
<%= f.submit 'Send', class: 'btn btn-success' %>
<% end %>
I haven't tried this out, but I did look at the source for options_from_collection_for_select, that uses value_for_collection under the hood; Defined as
def value_for_collection(item, value)
value.respond_to?(:call) ? value.call(item) : public_or_deprecated_send(item, value)
end
(See Rails Source Code and apidock.com)
Related
I have two tables class_details and user_classes. user_classes table is dependent of user table and class_details and class_details is independent of user table. Now my requirement is that when i click a button few details must be saved to the database which belong to different tables. User dependent table are only getting saved to database and not the user independent tables and i am getting error undefined method class_detail for nil:NilClass
Controller code
def update_profile
if #user.update(user_params)
redirect_to profile_index_path, notice: 'Profile was successfully updated.'
else
render :index
end
end
end
private
def set_user
#user = User.find(current_user.id)
#user.fee || #user.build_fee
#user.user_class || #user.build_user_class
end
def user_params
params.require(:user).permit(:name, fee_attributes: %i[id fee_hour fee_month], user_class_attributes: %i[id class_detail [id class_name class_category]])
end
class_detail.rb
class ClassDetail < ApplicationRecord
has_one :user_class, dependent: :destroy
end
user_class.rb
class UserClass < ApplicationRecord
belongs_to :user
belongs_to :class_details
validates_presence_of :user_id
end
user.rb
has_one :fee, dependent: :destroy
accepts_nested_attributes_for :fee
has_one :user_class, dependent: :destroy
view code
<%= form_for(#user, url: {action: 'update_profile'}, html: {class: 'm-form m-form--fit m-form--label-align-right'}) do |f| %>
<%= f.fields_for :fee, #user.fee do |u| %>
<%= u.number_field :fee_hour, class: 'form-control m-input', placeholder: t('.fee_for_hour') %>
<% end %>
<%= f.fields_for :user_class, #user.user_class do |k| %>
<%= f.fields_for :class_detail, #user_class.class_detail do |c| %>
<%= c.text_field :class_name, class: 'form-control m-input' %>
<% end %>
<% end %>
Can anyone help me updating user independent table! Thank you in advance
params.require(:user).permit(:name, fee_attributes: %i[id fee_hour fee_month], user_class_attributes: %i[id class_detail [id class_name class_category]])
That means you want to update class_detail from user_class, but you need to define nested attributes:
class UserClass < ApplicationRecord
belongs_to :user
belongs_to :class_details
accepts_nested_attributes_for :class_details, update_only: true
validates_presence_of :user_id
end
Also, the form must look like this:
<%= form_for(#user, url: {action: 'update_profile'}, html: {class: 'm-form m-form--fit m-form--label-align-right'}) do |f| %>
<%= f.fields_for :fee, #user.fee do |u| %>
<%= u.number_field :fee_hour, class: 'form-control m-input', placeholder: t('.fee_for_hour') %>
<% end %>
<%= f.fields_for :user_class, #user.user_class do |k| %>
<%= k.fields_for :class_detail, #user.user_class.class_detail do |c| %>
<%= c.text_field :class_name, class: 'form-control m-input' %>
<% end %>
<% end %>
<% end %>
And in your controller:
def user_params
params.require(:user).permit(:name, fee_attributes: %i[id fee_hour fee_month], user_class_attributes: [:id, { class_detail: %i[class_name class_category] }])
end
Edited:
That all means class_details and user_class are associated to the user already. Build references model - child-child-model - child-parent-model from the single call not possible. You can build this references in the edit action. For example:
def edit
#user.create_user_class!(class_detail: ClassDetail.find(n)) unless #user.user_class
end
I have a few models in my project : Request, Work, Car and Employee. Work is an intermediate model between Request and Car/Employee.
Here are the associations:
Request
has_many :works, dependent: :destroy
def performers
works.map {|x| x.performer}
end
Work
belongs_to :request
belongs_to :performer, polymorphic: true
Car
has_many :works, as: :performer
has_many :requests, through: :works, as: :performer
Employee
has_many :works, as: :performer
has_many :requests, through: :works, as: :performer
View used to create works:
<%= form_for([#request, #work]) do |f| %>
<%= (f.collection_select :performer_id, Employee.all, :id, :name) if #request.type == "StaffRequest" %>
<%= (f.collection_select :performer_id, Car.all, :id, :select_info) if #request.type == "CarRequest" %>
<%= f.submit 'OK' %>
<% end %>
Work controller
def new
#work = #request.works.new
end
def create
#work = #request.works.new(work_params)
end
def work_params
params.require(:work).permit(:performer_id, :request_id)
end
The problem is that my performer_type column is always empty, it does not save the class name. What can be the problem? Any ideas?
It's empty because you did't pass it, you should add a hidden field for you form:
<%= form_for([#request, #work]) do |f| %>
<% if #request.type == "StaffRequest" %>
<%= (f.hidden_field :performer_type, value: "Employee") %>
<%= (f.collection_select :performer_id, Employee.all, :id, :name) %>
<% elsif #request.type == "CarRequest" %>
<%= (f.hidden_field :performer_type, value: "Car") %>
<%= (f.collection_select :performer_id, Car.all, :id, :select_info) %>
<% end %>
<%= f.submit 'OK' %>
<% end %>
Beside :performer_id, you have to pass the :performer_type also, one way to do this is via the form select_tag :
def create
#work = #request.works.new(work_params)
end
def work_params
# use :performer if you use :performer as in the select form field
params.require(:work).permit(:performer, :request_id)
# OR
# use :performer_id & :performer_type if you also use the hidden field
params.require(:work).permit(:performer_id, :performer_type, :request_id)
end
There is a good example (for Rails 4.2) of using a single select form field for polymorphic so you can write like:
<%= f.grouped_collection_select :global_performer, [ Car, Employee ], :all, :model_name, :to_global_id, :name %>
How to create grouped select box in Rails for polymorphic association using Global ID?
I have a problem with a form and strong parameters. I see many have gone before me with such problems but nothing suggested to them seems to work.
My form:
<%= form_for(#student) do |f| %>
<%= f.label :school_id %>
<%= f.text_field :school_id, class: 'form-control' %>
...
<%= f.fields_for :enrollments do |enrol_form| %>
<%= enrol_form.label :date , "Enrollment date", class: 'form-control' %>
<%= enrol_form.date_field :date , class: 'form-control' %>
<%= enrol_form.hidden_field :reason, value: "Entered on system" %>
<% end %>
...
<% end %>
Models:
class Student < ActiveRecord::Base
include PhoneValid
has_many :enrollments, inverse_of: :student
validates :enrollments, :presence => { message: "Must have at least one enrollment event" }
accepts_nested_attributes_for :enrollments
end
class Enrollment < ActiveRecord::Base
belongs_to :student
default_scope -> { order(date: :asc) }
validates :date, presence:true
validates :enroll_wd, inclusion: {in: %w(ENROLL WD), messages: "%{value} must be either WD or ENROLL"}
end
Controller:
class StudentsController < ApplicationController
def create
#student = Student.new(student_params)
#student.save
end
def student_params
params.require(:student).permit(:school_id, :cellphone, :attendance_officer_id, :attendance_officer_type, :language_preferred, {enrollment_attributes: [:date, :reason, :id]})
end
end
The output of my form according to debug(params) is:
--- !ruby/hash:ActionController::Parameters
utf8: "✓"
authenticity_token: >cuk8Y+d8fHhJ3mU7wtRYtyDJoiYaG8lfzHvdGVBUI+1qmH7xQr20BHsBAFRT4r1EfDb/MMbxMq8rbKw3Cf2Y1A==
student: !ruby/hash:ActionController::Parameters
school_id: '234234'
cellphone: '234234234'
language_preferred: en
enrollments_attributes: !ruby/hash:ActionController::Parameters
'0': !ruby/hash:ActionController::Parameters
date: '2015-07-10'
reason: Entered on system
attendance_officer_id: '8'
attendance_officer_type: User
commit: Save student
controller: students
action: create
The output of student_params is:
{"school_id"=>"234234", "cellphone"=>"234234234", "attendance_officer_id"=>"8", "attendance_officer_type"=>"User", "language_preferred"=>"
I've been trying every different format of student_params that I can find on in the forums and have concluded that the problem must be somewhere else - am I creating the form correctly? Is there something wrong in my models?
Thank you for any help you can give me.
Walter
Try changing your student_params to below
def student_params
params.require(:student).permit(:school_id, :cellphone, :attendance_officer_id, :attendance_officer_type, :language_preferred, enrollments_attributes: [:date, :reason, :id])
end
Each "User" has one "Move".
Each "Move" has many "Neighborhood Preferences".
I want to create a form on the "/user/(:id)/edit" page that lets a person edit their "move", and "neighborhood_preferences".
Currently, the form displays correctly. But when I submit the form, I get this error Move(#2168853040) expected, got ActionController::Parameters(#2158484920).
How can I save both a new move, and the neighborhood_preferences?
View for Users#edit
<%= form_for(#user) do |f| %>
<%= hidden_field_tag "user[move][neighborhood_ids][]", nil %>
<% #neighborhoods.each do |n| %>
<%= check_box_tag "user[move][neighborhood_ids][]",
n.id, # the value to submit
#user.move.neighborhood_ids.include?(n.id), # Check the box on load
id: dom_id(n) # add a unique category based on the object
%>
<%= label_tag dom_id(n), n.name %>
<br/>
<% end %>
<%= f.submit "Save Changes" %>
<% end %>
Controller for Users#edit
def edit
#user = User.find(params[:id])
#neighborhoods = Neighborhood.all
end
private
def user_params
params.require(:user).permit(
:email,
:age,
:gender,
:university,
:grad_year,
:occupation,
:company,
# Allow form to submit neighborhood_ids for a user's move.
move: [neighborhood_ids: []]
)
end
Models
class User < ActiveRecord::Base
# attr_accessible :provider, :uid, :name, :email
validates_presence_of :name
has_one :move
accepts_nested_attributes_for :move, allow_destroy: true
class Move < ActiveRecord::Base
belongs_to :user
has_many :neighborhood_preferences
has_many :neighborhoods, through: :neighborhood_preferences
accepts_nested_attributes_for :neighborhood_preferences, allow_destroy: true
end
class NeighbhoodPreference < ActiveRecord::Base
belongs_to :neighborhood
belongs_to :move
end
I'm developing an app for college where a user can log on & upload details of a hiking trail.
So far everything is working & I have also implemented a nested form for photos in each hiking trail. A user can log-on & create a hike.
I would like to display all the hikes which the user created in there show/profile page but when I've set up the relationships in my database & the has_many & belongs_to options in my model. I've also tried to do this with nested accepts_nested_attributes_for :hikingtrails it does none of this works.
I've checked my database when a hikingtrail is created by a user it is not updating the user_id field in the table.
I'm not sure if I'm approaching this entirely the wrong way, should I be looking at polymorphic associations?
class User < ActiveRecord::Base
attr_accessible :user_name, :email, :password, :password_confirmation, :photos_attributes, :hikingtrails_attributes
has_many :hikingtrails
accepts_nested_attributes_for :hikingtrails, :allow_destroy => :true, :reject_if => :all_blank
class Hikingtrail < ActiveRecord::Base
attr_accessible :description, :name, :looped, :photos_attributes,:directions_attributes, :user_id
has_many :photos
has_many :trails
has_many :directions
belongs_to :user
users/show.html.erb
<div class="page-header">
<h1>Your Profile</h1>
</div>
<p>
<b>username:</b>
<%= #user.user_name %>
</p>
<p>
<b>email:</b>
<%= #user.email %>
</p>
<h4>Small Photos</h4>
<% #user.photos.each do |photo| %>
<%= image_tag photo.image_url(:thumb).to_s %>
<% end %>
<h4>Hiking Trails</h4>
<% #user.hikingtrails.each do |hk| %>
<%= hk.name %>
<% end %>
<%= link_to "Edit your Profile", edit_user_path(current_user), :class => 'btn btn-mini' %>
You didn't add :user_id to your accessible attributes in the Hikingtrail model. Try the following:
attr_accessible :description,
:duration_hours,
:duration_mins,
:name,
:looped,
:addr_1,
:addr_2,
:addr_3,
:country,
:latitude,
:longitude,
:photos_attributes,
:trails_attributes,
:directions_attributes,
:user_id
UPDATE:
After seeing the form code, I think it's probably not necessary to do the above and could potentially also be unsafe. Instead, don't set the user_id through mass assignment, but handle user assignment in your controller like so:
class HikingtrailsController < ApplicationController
# ...
def create
#hikingtrail = Hikingtrail.new(params[:hikingtrail])
#hikingtrail.user = current_user
if #hikingtrail.save
# ...
else
# ...
end
end
end
Hope this helps :)