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 %>
Related
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 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!
I am trying to store client_id in join table: clients_orders after submitting the form below.
I set the tables in this way so I can look up all the orders a client has made.
I am using rails 4 with devise and simple form.
models
class Order < ActiveRecord::Base
belongs_to :user
#has_and_belongs_to_many :clients
belongs_to :clients #solution
end
class Client < ActiveRecord::Base
#has_and_belongs_to_many :orders
as_many :orders, dependent: :destroy #solution
end
orders form
<%= simple_form_for(#order) do |f| %>
<%= f.error_notification %>
<%= f.association :client, collection: Client.all, label_method: :name, value_method: :id, prompt: "Choose a Client" } %>
<%= etc... %>
<%= f.submit %>
<% end %>
with the current code above, the join table clients_orders does not update
create_table "clients_orders", id: false, force: true do |t|
t.integer "client_id"
t.integer "order_id"
end
order controller
class OrdersController < ApplicationController
# GET /orders/new
def new
#order = Order.new
end
# POST /orders
# POST /orders.json
def create
#order = Order.new(order_params)
#order.user_id = current_user.id
respond_to do |format|
if #order.save
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render :show, status: :created, location: #order }
else
format.html { render :new }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
# Never trust parameters from the scary internet, only allow the white list through.
def order_params
params.require(:order).permit(:code, :client_id, :user_id, :memo, :status, items_attributes: [:id, :name, :_destroy])
end
end
For future reference:
this is a simple one-to-many relationship. All you have to do to access a client's orders is to set up the has_many :orders in the User model and belongs_to :user in Order model. Then you can use collection methods like current_user.orders and it will get all of that specific user's orders for you. Just assign it to the user with #order = current_user.orders.build(:order_params)
You aren't whitelisting the correct parameters in your create action.
When dealing with has_and_belongs_to_many associations, you're dealing with multiple objects on each side, so the attributes you're whitelisting are plural, not singular.
You need to be whitelisting client_ids, not client_id.
Also, I'm pretty sure your form is wrong. You have it setup as though client is a has_one relationship. I think you want the plural version there as well.
<%= f.association :clients, #...
# ^----- add an 's'
If you really intended for the form to model a singular relationship, then you'll need to massage the data somewhere before saving your model. Here's one way to do it:
def create
#order = Order.new(order_params)
#order.client_ids << params[:order][:client_id]
#order.user_id = current_user.id
# save and respond...
end
If you go this route, then just remove :client_id from your parameters whitelist rather than pluralizing it.
I have a form that lets me create new blog posts and I'd like to be able to create new categories from the same form.
I have a habtm relationship between posts and categories, which is why I'm having trouble with this.
I have the following 2 models:
class Post < ActiveRecord::Base
has_and_belongs_to_many :categories
attr_accessible :title, :body, :category_ids
accepts_nested_attributes_for :categories # should this be singular?
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :posts
attr_accessible :name
end
My form lets me pick from a bunch of existing categories or create a brand new one. My form is as follows.
# using simple_form gem
.inputs
= f.input :title
= f.input :body
# the line below lets me choose from existing categories
= f.association :categories, :label => 'Filed Under'
# I was hoping that the code below would let me create new categories
= f.fields_for :category do |builder|
= builder.label :content, "Name"
= builder.text_field :content
When I submit my form, it gets processed but the new category is not created. My command prompt output tells me:
WARNING: Can't mass-assign protected attributes: category
But, if I add attr_accessible :category, I get a big fat crash with error message "unknown attribute: category".
If I change the fields_for target to :categories (instead of category) then my form doesn't even display.
I've spent a while trying to figure this out, and watched the recent railscasts on nested_models and simple_form but couldn't get my problem fixed.
Would this be easier if I was using a has_many :through relationship (with a join model) instead of a habtm?
Thanks to everyone who answered. After much trial and error, I managed to come up with a fix.
First of all, I switched from a HABTM to a has_many :through relationship, calling my join model categorization.rb (instead of categorizations_posts.rb) - NB: the fix detailed below will likely work with a HABTM too:
Step 1: I changed my models to look like this:
# post.rb
class Post < ActiveRecord::Base
has_many :categorizations
has_many :categories, :through => :categorizations
attr_accessible :title, :body, :category_ids
accepts_nested_attributes_for :categories
end
#category.rb
class Category < ActiveRecord::Base
has_many :categorizations
has_many :posts, :through => :categorizations
attr_accessible :name, :post_ids
end
#categorization.rb
class Categorization < ActiveRecord::Base
belongs_to :post
belongs_to :category
end
From the post model above: obviously, the accessor named :category_ids must be present if you want to enable selecting multiple existing categories, but you do not need an accessor method for creating new categories... I didn't know that.
Step 2: I changed my view to look like this:
-# just showing the relevent parts
= fields_for :category do |builder|
= builder.label :name, "Name"
= builder.text_field :name
From the view code above, it's important to note the use of fields_for :category as opposed to the somewhat unintuitive fields_for :categories_attributes
Step 3
Finally, I added some code to my controller:
# POST /posts
# POST /posts.xml
def create
#post = Post.new(params[:post])
#category = #post.categories.build(params[:category]) unless params[:category][:name].blank?
# stuff removed
end
def update
#post = Post.find(params[:id])
#category = #post.categories.build(params[:category]) unless params[:category][:name].blank?
# stuff removed
end
Now, when I create a new post, I can simultaneously choose multiple existing categories from the select menu and create a brand new category at the same time - it's not a case of one-or-the-other
There is one tiny bug which only occurs when editing and updating existing posts; in this case it won't let me simultaneously create a new category and select multiple existing categories - if I try to do both at the same time, then only the existing categories are associated with the post, and the brand-new one is rejected (with no error message). But I can get round this by editing the post twice, once to create the new category (which automagically associates it with the post) and then a second time to select some additional existing categories from the menu - like I said this is not a big deal because it all works really well otherwise and my users can adapt to these limits
Anyway, I hope this helps someone.
Amen.
In your form you probably should render the fields_for once per category (you can have multiple categories per post, hence the habtm relation). Try something like:
- for category in #post.categories
= fields_for "post[categories_attributes][#{category.new_record? ? category.object_id : category.id}]", category do |builder|
= builder.hidden_field :id unless category.new_record?
= builder.label :content, "Name"
= builder.text_field :content
I have made my application and my nested form works with HABTM.
My model is :
class UserProfile < ActiveRecord::Base
attr_accessible :name, :profession
has_and_belongs_to_many :cities
belongs_to :user
attr_accessible :city_ids, :cities
def self.check_city(user,city)
user.cities.find_by_id(city.id).present?
end
end
class City < ActiveRecord::Base
attr_accessible :city_name
has_and_belongs_to_many :user_profiles
end
In my form I have:
-# just showing the relevent parts
= f.fields_for :cities do|city|
= city.text_field :city_name
And at my controller:
def create
params[:user_profile][:city_ids] ||= []
if params[:user_profile][:cities][:city_name].present?
#city= City.create(:city_name=>params[:user_profile][:cities][:city_name])
#city.save
params[:user_profile][:city_ids] << #city.id
end
#user=current_user
params[:user_profile].delete(:cities)
#user_profile = #user.build_user_profile(params[:user_profile])
respond_to do |format|
if #user_profile.save
format.html { redirect_to #user_profile, notice: 'User profile was successfully created.' }
format.json { render json: #user_profile, status: :created, location: #user_profile }
else
format.html { render action: "new" }
format.json { render json: #user_profile.errors, status: :unprocessable_entity }
end
end
end
def update
params[:user_profile][:city_ids] ||= []
if params[:user_profile][:cities][:city_name].present?
#city= City.create(:city_name=>params[:user_profile][:cities][:city_name])
#city.save
params[:user_profile][:city_ids] << #city.id
end
#user=current_user
params[:user_profile].delete(:cities)
#user_profile = #user.user_profile
respond_to do |format|
if #user_profile.update_attributes(params[:user_profile])
format.html { redirect_to #user_profile, notice: 'User profile was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user_profile.errors, status: :unprocessable_entity }
end
end
end
This code works.
Maybe you should try it with (not testet):
attr_accessible :category_attributes
And HBTM relations arent really recommened... But I use them on my own :P