I have 3 models User, House and Order.
Order Model
class Order < ActiveRecord::Base
belongs_to :from_house, :class_name => "House"
belongs_to :to_house, :class_name => "House"
belongs_to :user
accepts_nested_attributes_for :from_house, :to_house, :user
end
My House Model.
class House < ActiveRecord::Base
belongs_to :user
belongs_to :place
belongs_to :city
end
My user model.
class User < ActiveRecord::Base
has_many :orders
has_many :houses
end
In my order form I have something like this
<%= form_for #order do |f| %>
... # order fields
<%= f.fields_for :user do |i| %>
... # your from user forms
<% end %>
<%= f.fields_for :from_house do |i| %>
... # your from house forms
<% end %>
<%= f.fields_for :to_house do |i| %>
... # your to house forms
<% end %>
...
<% end %>
I haven't changed much in controller from the default. The controller code
def create
#order = Order.new(order_params)
respond_to do |format|
if #order.save
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render action: 'show', status: :created, location: #order }
else
format.html { render action: 'new' }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
def order_params
params.require(:order).permit( :shift_date, user_attributes: [:name, :email, :ph_no], from_house_attributes: [:place_id, :floor, :elevator, :size], to_house_attributes: [:place_id, :floor, :elevator])
end
When I submit the form, as expected a Order gets created with a new from_house and to_house along with a new user. But however my user_id in house table remains NULL. How can I make the houses(both from and to) reference the user created after submit.
The User is not logged in, So there is no current_user. We have to create a new user based on the details given. That user has to be associated with the houses (from and to).
I hope I'm clear. If not please let me know.
P.S: This question is an extension to this Ruby on rails: Adding 2 references of a single model to another model
I think this change in app/models/order.rb should do the trick:
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :from_house, class_name: 'House'
belongs_to :to_house, class_name: 'House'
accepts_nested_attributes_for :user, :from_house, :to_house
validates :user, :from_house, :to_house, presence: true
def from_house_attributes=(attributes)
fh = build_from_house(attributes)
fh.user = self.user
end
def to_house_attributes=(attributes)
th = build_to_house(attributes)
th.user = self.user
end
end
Now, try this in your Rails console:
params = { user_attributes: { name: 'New name', email: 'name#example.com' }, from_house_attributes: { name: 'From house name' }, to_house_attributes: { name: 'to house name' } }
o = Order.new(params)
o.save
o.from_house
o.to_house
Cheers!
Related
I have a 3 models. User, CV, and Language. A User has one CV. A CV has many Languages. The User has many Languages through its CV. When I try to save the form I get an error that the Language does not have a User ID. How can I get the User ID to pass through the CV and to the Language in my form?
The CV is receiving the User ID properly. Languages is not.
I am using the Simple-Form and Cocoon gems.
Simplified version of form
= simple_form_for(#cv, url: user_cvs_path) do |f|
= f.simple_fields_for :languages do |language|
From User Model
has_one :cv, dependent: :destroy
has_many :languages, through: :cv, inverse_of: :user
From Cv Model
belongs_to :user
has_many :languages, dependent: :destroy
accepts_nested_attributes_for :languages, allow_destroy: true
From Language Model
belongs_to :user
belongs_to :cv
From the CV Controller
before_action :set_user
def new
#cv = #user.build_cv
#cv.languages.build
end
def create
#cv = #user.create_cv(cv_params)
respond_to do |format|
if #cv.save
format.html { redirect_to user_cv_url(#user, #cv), notice: 'Cv was successfully created.' }
format.json { render :show, status: :created, location: #cv }
else
format.html { render :new }
format.json { render json: #cv.errors, status: :unprocessable_entity }
end
end
end
def cv_params
params.require(:cv).permit(
:user_id,
:first_name,
:middle_name,
:last_name,
... # lots of params left out for brevity
languages_attributes: [
:id,
:cv_id,
:user_id,
:name,
:read,
:write,
:speak,
:listen,
:_destroy])
end
def set_user
#user = current_user if user_signed_in?
end
Your Language model does not need the belongs_to :user. Language belongs to CV and CV belongs to User, so the relation between Language and User is already in place. If you need to access the user for a specific language you can write #language.cv.user
To solve your problem just remove the belongs_to :user from the Language model, remove the user_id from languages_attributes, and remove the user_id from languages table.
Good night friends!
In a form with many through, I need to display all the objects of a given class (tool), with a checkbox field and text field next to it. My form is as follows:
= simple_form_for #service, html: { class: 'form-horizontal' } do |f|
- #tools.each do |tool|
= f.simple_fields_for :instrumentalisations, tool do |i|
= i.input :tool_id, tool.id, as: :check_boxes
= i.input :amount
But I'm getting the following error:
Undefined method `tool_id 'for # <Tool: 0x007faef0327c28>
Did you mean To_gid
Models
class Service < ApplicationRecord
has_many :partitions, class_name: "Partition", foreign_key: "service_id"
has_many :steps, :through => :partitions
has_many :instrumentalisations
has_many :tools, :through => :instrumentalisations
accepts_nested_attributes_for :instrumentalisations
end
class Tool < ApplicationRecord
has_many :instrumentalisations
has_many :services, :through => :instrumentalisations
accepts_nested_attributes_for :services
end
class Instrumentalisation < ApplicationRecord
belongs_to :service
belongs_to :tool
end
Controller
def new
#service = Service.new
#service.instrumentalisations.build
end
def edit
#tools = Tool.all
end
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 }
format.json { render json: #service.errors, status: :unprocessable_entity }
end
end
end
def service_params
params.require(:service).permit(:name, :description, :price, :runtime, :status, step_ids: [], instrumentalisations_attributes: [ :id, :service_id, :tool_id, :amount ])
end
Thank you!
the error is quite simple: tool doesn't has a tool_id method. BUT, why are you asking this to a tool object instead of a instrumentalisation object?
So, you're trying to create some instrumentalisations but you're passing a tool as object:
f.simple_fields_for :instrumentalisations, **tool** do |i|
fields_for requires a record_name, whith in this case is :instrumentalisations and the 2nd arg is the record_object, which should be an instrumentalisations object and not a tool object.
So to fix it would have to pass an instrumentalisation object. You can accomplish that by:
f.simple_fields_for :instrumentalisations, Instrumentalisation.new(tool: tool) do |i|
Of course this isn't the best solution since if you edit this object would be building a lot of new instrumentalisations.
I'd recommend the cocoon gem, which makes it easier to handle nested forms!
I'm encountering an error when trying to create a new nested form.
I have 3 models:
class Child < ActiveRecord::Base
has_many :hires
has_many :books, through: :hires
end
class Hire < ActiveRecord::Base
belongs_to :books
belongs_to :children
accepts_nested_attributes_for :books
accepts_nested_attributes_for :children
end
class Book < ActiveRecord::Base
has_many :hires
has_many :children, through: :hires
belongs_to :genres
end
I'm trying to set up a view which allows children to 'hire' 2 books.
The view looks like this:
<%= form_for(#hire) do |f| %>
<%= hires_form.label :child %><br>
<%= hires_form.select(:child, Child.all.collect {|a| [a.nickname, a.id]}) -%>
<%= f.fields_for :books do |books_form| %>
<%= books_form.label :book %><br>
<%= books_form.select(:book, Book.all.collect {|a| [a.Title, a.id]}) -%>
<%= books_form.label :book %><br>
<%= books_form.select(:book, Book.all.collect {|a| [a.Title, a.id]}) -%>
<% end %>
<%= f.submit %>
<% end %>
The controller looks like this:
class HiresController < ApplicationController
...
def new
#hire = Hire.new
2.times { #hire.books.build }
end
def create
#hire = Hire.new(hire_params)
respond_to do |format|
if #hire.save
format.html { redirect_to #hire, notice: 'Hire was successfully created.' }
format.json { render :show, status: :created, location: #hire }
else
format.html { render :new }
format.json { render json: #hire.errors, status: :unprocessable_entity }
end
end
end
...
private
# Use callbacks to share common setup or constraints between actions.
def set_hire
#hire = Hire.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def hire_params
params.require(:hire).permit(:book, :child, books_attributes: [:id, :book, :child, :_destroy])
end
end
I'm getting the error:
undefined method `build' for nil:NilClass
I feel this is something obvious that i'm missing but any help would be great!
belongs_to :books
belongs_to :children
You need to singularize these.
belongs_to :book
belongs_to :child
Also see section 2.4 of the rails guides as a reference "The has_many :through Association":
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
Keep in mind that you are using a belongs_to on the Hire object.
Notice the methods that are added when using the belongs_to association:
association(force_reload = false)
association=(associate)
build_association(attributes = {})
create_association(attributes = {})
create_association!(attributes = {})
So you should be able to use the method build_book on the Hire object (eg. #hire.build_book of #hire.build_child).
The methods added by the has_many association are:
collection(force_reload = false)
collection<<(object, ...)
collection.delete(object, ...)
collection.destroy(object, ...)
collection=(objects)
collection_singular_ids
collection_singular_ids=(ids)
collection.clear
collection.empty?
collection.size
collection.find(...)
collection.where(...)
collection.exists?(...)
collection.build(attributes = {}, ...)
collection.create(attributes = {})
collection.create!(attributes = {})
Which can be used on your Book and Child objects. For example: #book.childeren.build or #child.books.build.
For reference see the rails guides section 4.2 and 4.3 'Methods Added by ..':
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
I'm a newbie in rails and trying to implement image uploading to ftp with 'carrierwave-ftp' gem. For image uploading, I have two controllers. First one is 'events_controller' while the second one is 'events_pictures_controller'.
Pictures are getting uploading to ftp. But the problem is that when I'm deleting a single picture, it is destroying the entire event. Please help!
Here is my Events Model:
class Event < ActiveRecord::Base
has_many :event_pictures, dependent: :destroy
accepts_nested_attributes_for :event_pictures, allow_destroy: true
validates_presence_of :name, :date
end
Here is my EventPictures Model:
class EventPicture < ActiveRecord::Base
mount_uploader :picture_title, EventPicturesUploader
validates_presence_of :picture_title
belongs_to :event, dependent: :destroy
end
Events Controller:
def index
#events = Event.all.order('date DESC')
end
def show
#event_pictures = #event.event_pictures.all
end
def new
#event = Event.new
#event_picture = #event.event_pictures.build
end
def edit
end
def create
#event = Event.new(event_params)
respond_to do |format|
if #event.save
params[:event_pictures]['picture_title'].each do |a|
#event_picture = #event.event_pictures.create!(:picture_title => a, :event_id => #event.id)
end
format.html { redirect_to #event, notice: 'Event was successfully created.' }
else
format.html { render :new }
end
end
end
def destroy
#event = Event.find params[:id]
#event.destroy
redirect_to events_url
end
private
def set_event
#event = Event.find(params[:id])
end
def event_params
params.require(:event).permit(:name, :date, event_pictures_attributes: [:id, :event_id, :picture_title])
end
This is the Destroy method in EventPictures Controller
def destroy
#event_picture = EventPicture.find params[:id]
#event_picture.destroy
redirect_to "events_url"
end
Meanwhile in the events.show.html.erb, I have this:
<% #event_pictures.each do |p| %>
<%= link_to image_tag(p.picture_title_url, :class => 'event-img'), image_path(p.picture_title_url) %>
<%= link_to 'Delete', p, method: :delete, data: { confirm: "Are you sure?" } %>
<% end %>
In your EventPicture model you have dependent: :destroy on the association which means that when the picture will deleted the corresponding events too. So just edit the association and make it:
belongs_to :event
And you have dependent destroy on the Event model so when a event will be deleted the corresponding pictures too will get deleted which is correct.
Hope this helps.
I believe your error lies with this line
belongs_to :event, dependent: :destroy
This is telling the EventPicture model to delete its parent model Event when it is deleted.
Replace with
belongs_to :event
I have to models:
class Patient < ActiveRecord::Base
attr_accessible :bis_gultigkeit, :geburtsdatum, :krankenkassennummer, :kvbereich, :landercode, :name, :namenszusatz, :plz, :statuserganzung, :strasse, :titel, :versichertennumer, :versichertenstatus, :vorname, :wohnort, :geschlecht, :telefon, :email, :gewicht
has_many :diagnosis
end
class Diagnose < ActiveRecord::Base
attr_accessible :beschreibung, :code, :seite, :sicherheit, :typ, :patient_id
belongs_to :patient
end
How you can see the two models have an association.
So that i want to display on the patient show page all of his diagnosis.
def show
#patient = Patient.find(params[:id])
#diagnosis = #patient.diagnosis
respond_to do |format|
format.html # show.html.erb
format.json { render json: #patient }
end
end
And in my view i call:
<%= #diagnosis.inspect %>
But somehow i get the error:
uninitialized constant Patient::Diagnosi
I cannot explain me why i get this error? And why does it say Diagnosi? I mean my model name is Diagnose! Thanks
You can call Diagnose.class_name.pluralize to see how rails pluralizes it.
I guess it is "Diagnoses", so you shoudl call:
#diagnoses = #patient.diagnoses
and
<%= #diagnoses.inspect %>