I have the following models and associations:
class JuridicalPerson < ActiveRecord::Base
end
class Supplier < ActiveRecord::Base
belongs_to :juridical_person
delegate :company_name, :company_name=, :to => jurirical_person
end
The controler is:
def new
#supplier = Supplier.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #supplier }
end
end
The schema looks as follow:
create_table "suppliers", :force => true do |t|
t.integer "juridical_person_id"
...
end
create_table "juridical_people", :force => true do |t|
t.string "company_name"
...
end
Now when I try to render it in a view, I get the following error:
Supplier#company_name delegated to juridical_person.company_name, but juridical_person is nil: #(Supplier id: nil, juridical_person_id: nil, created_at: nil, updated_at: nil)
Extracted source (around line #9):
8: <%= f.label :company_name, "Company Name" %>
9: <%= f.text_field :company_name %>
Seems like the associated juridical_person is not being created at the time of delegation, but I can't figure out why. Even if I create it in the controller, the app will break when trying to update for the same reason. What am I missing?
remove = Change
delegate :company_name, :company_name=, :to => jurirical_person
To
delegate :company_name, :company_name, :to => jurirical_person
class JuridicalPerson < ActiveRecord::Base
has_many :suppliers
end
Related
I am unable to get my association to save in localhost:3000/controller_name/new. I believe it is due to belongs_to failing validation, but I am not sure how to fix it (beyond just dropping the association via requires:false/optional: true, the consequences of which I am not sure of). I created my association following this tutorial but it was for a previous version of rails.
I have a polymorphic address table that can belong to events, businesses, users, etc. I am trying to add it to event.
Address migration - you can see it references addressable:
class CreateAddresses < ActiveRecord::Migration[5.1]
def change
create_table :addresses do |t|
t.string :address
t.decimal :latitude, null: false, precision: 10, scale: 6, index: true
t.decimal :longitude, null: false, precision: 10, scale: 6, index: true
t.references :addressable, polymorphic: true, index: true
end
end
end
Address model:
class Address < ApplicationRecord
belongs_to :addressable, polymorphic: true
end
Event model:
class Event < ApplicationRecord
has_one :address, as: :addressable
accepts_nested_attributes_for :address
end
Event Controller:
class EventsController < ApplicationController
#...stuff...
# GET /events/new
def new
#event = Event.new
#event.address = #event.build_address
##event.address = Address.new(addressable: #event)
##event.address = #event.create_address
##event.address = #addressable.User.new
end
#...stuff...
You can see I tried multiple methods to create the event's address, they mostly create the below item, the ones using addressable cause a Nil crash.
#<Address id: nil, address: nil, latitude: nil, longitude: nil, addressable_type: "Event", addressable_id: nil>
Event Form (Uses Simple_form gem):
<%= simple_form_for #event do |f| %>
<%= f.input :name %>
<%= f.input :description %>
<%= f.simple_fields_for :address do |address| %>
<%= render :partial => 'shared/address/form', :locals => {:f => address} %>
<% end %>
<%= f.button :submit %>
<% end %>
Address form partial:
<!-- Google Maps Must be loaded -->
<% content_for :head do %>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCMh8-5D3mJSXspmJrhSTtt0ToGiA-JLBc&libraries=places"></script>
<% end %>
<div id="map"></div>
<%= f.input :address %>
<%= f.input :latitude %>
<%= f.input :longitude %>
Forms render fine. When I try to save I get
Started POST "/events" for 127.0.0.1 at 2017-07-01 16:06:23 -0400
Processing by EventsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"R0zlSs3UUNV3x8sQn5ocmE4jP12uOsFza7FezBAuhP4sw2MhF1OhixF8sAfDsLpfMEX7x5rhJ9HZfbKna8ncEA==", "event"=>{"name"=>"asd", "description"
=>"asd", "address_attributes"=>{"address"=>"asd", "latitude"=>"1", "longitude"=>"1"}}, "commit"=>"Create Event"}
(0.1ms) begin transaction
(0.1ms) rollback transaction
And I am kept on the new page. If I insert a byebug into create and print out #event.errors it shows:
#<ActiveModel::Errors:0x007fb29c34a9a8 #base=#<Event id: nil, name: "asd", description: "asd", min_users: nil, max_users: nil, start_time: nil, recurring: nil, created_at: nil, upd
ated_at: nil>, #messages={:"address.addressable"=>["must exist"]}, #details={:"address.addressable"=>[{:error=>:blank}]}>
How can I create the address.addressable? What are the consequences of turning off the requires validation as some SO answers suggest?
run rake db:schema:dump, and then check file inside db/schema.rb, make sure you have 2 fields as follow
* t.integer :addressable_id,
* t.string :addressable_type
and for more detail here is link about Activerecord Polymorphic Associations, if you have problem with your schema, then you can run migration as follow
t.references :addressable, polymorphic: true, index: true
as event has many address through polymorphic association, you can use this link to create the address
and below is sample code
#address = #event.addresses.build(attributes = {}, ...)
you may use #address not #event.address
Discovered the issues and wrote a blog post discussing this in depth. Essentially I was encountering 2 separate problems
1.The error I was receiving - "address.addressable"=>["must exist"]. address.addressable is the 'parent' table's tuple ID. In my case it is the Event ID. This error is trying to tell me that this foreign key is missing from the new address when we try to save it in the controller's create function. Like I said in the question, you can set optional:true to ignore this problem, and it somehow magically gets filled in after saving the Event. Or you can manually assign it in the create function before it saves.
def create
#event = Event.new(event_params)
#event.address.addressable = #event #<<<<<<<<<<< manually assign address.addressable
respond_to do |format|
if #event.save #Saves the event. Addressable has something to reference now, but validation does not know this in time
format.html { redirect_to #event, notice: 'Event was successfully created.' }
format.json { render :show, status: :created, location: #event }
else
#dont forget to remove the 'byebug' that was here
format.html { render :new }
format.json { render json: #event.errors, status: :unprocessable_entity }
end
end
end
2.Event ID was a string. In my address migration I was using t.references :addressable, polymorphic: true, index: true which is an alias for and addressable_id of integer type. I needed to change my migration to use string IDs - so delete the references line and add this in instead.
t.string :addressable_id, index: true
t.string :addressable_type, index: true
This is covered in slightly more detail in the blog post.
This question follows up on Rails has_many :through association: save instance into join table and I am restating things here for more clarity.
In our Rails app, there are 3 models:
class User < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :calendars, through: :administrations
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
class Calendar < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :users, through: :administrations
end
And here are the corresponding migrations:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.integer :total_calendar_count
t.integer :owned_calendar_count
t.timestamps null: false
end
end
end
class CreateAdministrations < ActiveRecord::Migration
def change
create_table :administrations do |t|
t.references :user, index: true, foreign_key: true
t.references :calendar, index: true, foreign_key: true
t.string :role
t.timestamps null: false
end
end
end
class CreateCalendars < ActiveRecord::Migration
def change
create_table :calendars do |t|
t.string :name
t.timestamps null: false
end
end
end
Here is what we are trying to accomplish:
When a logged in user (current_user) creates a calendar, we should:
Create a new #calendar and save it to the Calendar table
Assign the "Creator" role to the user (current_user) for this newly created calendar through the Role column in the Administration table
Increment the total_calendar_count and the owner_calendar_count columns of the User table
In order to do that, we think we need to work on calendars#create.
In the CalendarsController, we already have the following code:
def create
#calendar = current_user.calendars.create(calendar_params)
if #calendar.save
flash[:success] = "Calendar created!"
redirect_to root_url
else
render 'static_pages/home'
end
end
And we collect data from users through the following _calendar_form.html.erb form:
<%= form_for(#calendar) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_field :name, placeholder: "Your new calendar name" %>
</div>
<%= f.submit "Create", class: "btn btn-primary" %>
<% end %>
We are considering updating the controller as follows:
def create
#calendar = current_user.calendars.create(calendar_params)
#current_user.total_calendar_count += 1
#current_user.owned_calendar_count += 1
current_user.administrations << #calendar.id
#calendar.administration.role = 'Creator'
if #calendar.save
flash[:success] = "Calendar created!"
redirect_to root_url
else
render 'static_pages/home'
end
end
ActiveRecord::AssociationTypeMismatch in CalendarsController#create
Administration(#70307724710480) expected, got Fixnum(#70307679752800)
unless record.is_a?(reflection.klass) || record.is_a?(reflection.class_name.constantize)
message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
raise ActiveRecord::AssociationTypeMismatch, message
end
end
app/controllers/calendars_controller.rb:7:in `create'
How can we make it work?
This line is actually causing the error: current_user.administrations << #calendar.id.
current.administrations expects an object of type Administration while you are passing a Fixnum into it.
You can accomplish the same functionality in the following way:
current_user.administrations.create(calendar_id: #calendar.id)
Edit:
As OP asked in comments that it is a good practice or not. See, there is rule that says that controllers should be skinny, and models should be fatty. Well, it means you should try to write minimum code, and all the logic and fetching of objects should be there in models. But that isn't the case in your code scenario. You should move your code into model, and then call that into your controller.
Here's how:
class User < ActiveRecord::Base
def add_calendar_and_role(calendar_id, role)
self.administrations.find_by(calendar_id: calendar_id).update(role: role)
end
end
This way, your code reduces to just:
current_user.add_calendar_and_role(#calendar.id, 'Creator')
And on the same way, you can further refactor your controller code.
I am trying to use the ancestry gem which I found by watching an old Ryan Bates Ancestry video and so I set up my my stuff like so:
Migration:
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.string :comment
t.string :author
t.integer :post_id
t.string :ancestry
t.index :ancestry
t.timestamps
end
end
end
Model:
class Comment < ActiveRecord::Base
belongs_to :post
has_ancestry
validates :comment, presence: true, length: {minimum: 15}
validates :author, presence: true
end
** Controller new Action: **
def new
post = Post.find_by(id: params[:post_id])
post.comments.new(:ancenstry => params[:parent_id])
end
So I think I have set up everything correctly. But when I run the following test:
it "should create a nested comment for a post" do
posted_comment = FactoryGirl.create(:comment, post_id: #post.id)
post :create, :post_id => #post.id, comment: {author: #comment.author, comment: #comment.comment, parent_id: #comment.id}
json = JSON.parse(response.body).to_json
binding.pry
parse_json(json, 'comment').to_json.should have_json_path('id')
end
And inspect the json after the binding pry:
{
"comment":{
"id":9,
"post_id":6,
"author":"Adam",
"comment":"Some Really long Valid Comment length of Something.",
"ancestry":null
}
}
The ancestry section is null. I have even tried tried changing parent_id to ancestry but that doesn't help either. Does any know what I am doing wrong? or have any ideas?
post.comments.new(:ancenstry => params[:parent_id])
The key of your hash is misspelled.
I have a nested object issue when creating a new item using forms. When I create a new Item within a form and view I created I get a nil on the Product object when trying to access it.
Here is my structure. I have a class called Item and a class called Product. There could be more than 1 item referring to the same Product.
class CreateItem < ActiveRecord::Migration
def change
create_table :items do |t|
t.integer :product_id
t.string :name
t.text :description
t.timestamps
end
end
end
class CreateProducts < ActiveRecord::Migration
def change
create_table :products do |t|
t.string :name
t.text :description
t.decimal :price
t.string :image_file_name
t.integer :inventory
t.timestamps
end
end
end
class Item< ActiveRecord::Base
belongs_to :product
belongs_to :itemstatus
end
class Product < ActiveRecord::Base
has_one :shop
accepts_nested_attributes_for :item
end
Controller Code:
def create
#item= Item.new(params[:item])
if #item.save
redirect_to #item, notice: "Item successfully created!"
else
render :new
end
end
The problem is happening when I go to show the created item. The Product object is nil. I'm not sure what I should be doing to get the Product Object correctly created and added in this process of creating a new Item.
Can someone help me?
Thanks!
params[:item] must be as the following:
#first example
params[:item] = {product_id: 1}
#second example
product = product.create(name: "", description: "", ..)
params[:item] = {product: product}
#third example
#item.product = product
#or
#item.product_id = params[:item][:product_id]
Try to do that:
#item.new(name: params[:item][:name], product_id: params[:item][:product_id], description: params[:item][:description])
help link
I have the following 2 tables defined in migrations
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :name
t.string :phone
t.string :email
t.string :address
t.string :resume
t.timestamps
end
end
end
Class CreateResumeSections < ActiveRecordMigration
def self.up
create_table :resume_sections do |t|
t.string :section_name
t.string :html
t.timestamps
end
end
end
I have following 2 models
class User
has_many :resume_sections, :dependent => :destroy
attr_accessor :section_layout
after_save :save_sections
private
def save_sections
self.section_layout = ###Someother logic here that sets this variable
end
end
class ResumeSection
belongs_to :user
end
In my users_controller, I have the following code
class UserController < ApplicationController
def create
#user = User.new(params[:user])
#user.save
#user.section_layout.each {|key,value|
rs = ResumeSection.new(:section_name => key, :html => value, :user => #user)
rs.save
}
end
end
In my view I have the following code
<% #user.resume_sections.each do |section| %>
<%= section.section_name %>
<%= section.html %>
<% end %>
I get Undefined method error for Nil:NilClass in the view. The expression #user.resume_sections is not returning to me the records that I just created and saved in the UsersController. Instead it returns nil to me. When I check the database the records are there.
Is the expression #user.resume_sections the correct expression to access these records?
Thanks
Paul
It seems to me that your you missed something in you migrations. ResumeSection needs to have and integer field called user_id. Just create a new migration that has something like this in it:
def change
add_column :resume_section, :user_id, :integer
end