simple_forms with two classes - ruby-on-rails

I have one controller for Property and other one for Country one property has one country
My Property model
class Property < ApplicationRecord
acts_as_paranoid
has_one :country, class_name: Country
belongs_to :company
accepts_nested_attributes_for :country
validates :name, presence: true
validates :address, presence: true
My Country model
class Country < ApplicationRecord
acts_as_paranoid
belongs_to :property
validates :name, presence: true
validates :isoalpha2, presence: true
validates :isolapha3, presence: true
And when I want to add one property with my view (new.html.erb)
<%= simple_form_for [#property, #country], url: property_new_path do |f| %>
<% if #property.errors.any? %>
<%= pluralize(#property.errors.count, "error") %> prohibited
this property from being saved:
<% #property.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% end %>
<%= f.input :name %>
<%= f.input :description %>
<%= f.input :address %>
<%= f.submit %>
I receive the following error:
undefined method `description' for #<Country:0x8de0b20>
I don't know why is taking the Country class instead of Property , because description is part of the Property controller
Thanks

That should be like
<%= simple_form_for [ #country, #property] do |f| %>
and routes should be in nested form
resources :countries do
resources :properties, except: [:index]
end
Hope this will work for you

Related

accepts_nested_attributes_for with validations and using find_or_create_by

I have a user model and a town model. A user belongs_to a town:
# models/user.rb
class User < ApplicationRecord
belongs_to :town
accepts_nested_attributes_for :town
validates :last_name, presence: true
end
# models/town.rb
class Town < ApplicationRecord
has_many :users
validates :name, presence: true
validates :name, uniqueness: true
end
You go to create a new user record: there is a text_box in order to put in the associated town's name. When submitted, the rails application should do the following:
use find_or_create_by. go and check if there already exists a town record with the name attribute passed in.
If a town record DOES exist with that given name attribute, just associate that existing town record to this new user record
If a town record DOES NOT exist with that given name attribute, then create a new town record with that name attribute, and associate that one to this user record
If any validations fail, do not create a user record or a town record and re-render the form.
I am having real trouble with this. This question suggests putting autosave on the belongs_to :town statement, as well as defining a method called autosave_associated_records_for_town. However: I just could not get that to work.
Appreciate it!
Please, try that solution. It works for me.
User
# user.rb
class User < ActiveRecord::Base
belongs_to :town
accepts_nested_attributes_for :town
validates :last_name, presence: true
end
Town
# town.rb
class Town < ActiveRecord::Base
has_many :users
validates :name, presence: true
end
Controller
# users_controller.rb
respond_to :html
def create
# ...
#user = User.new(user_params)
#user.town = Town.find_or_initialize_by(user_params[:town_attributes])
if #user.save
respond_with(#user)
else
render 'new'
end
end
# ...
def user_params
params.require(:user).permit(:last_name, :email, :town_id, town_attributes: [:name])
end
View
# users/_form.html.erb
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :email %><br>
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :last_name %><br>
<%= f.text_field :last_name %>
</div>
<%= f.fields_for :town, #town do |bldr| %>
<div class="field">
<%= bldr.label :name, 'Town name' %><br>
<%= bldr.text_field :name %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
UPDATE
Please consider to add validates_associated to user's validations as well.
Here is the related documentaion
class User < ActiveRecord::Base
belongs_to :town
accepts_nested_attributes_for :town
validates :last_name, presence: true
validates :town, presence: true
validates_associated :town
end
Generaly speaking, you could remove validates :town, presence: true in that case. Validations will work without it.

Rails - checkbox form from array

I have a admin controller to create "Locations", inside of which is a form. In the form you can create a new "Location" and give it a name, description, and "exits".
<%= form_for #location do |f| %>
<p>
<%= f.label :name %><br>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :description %><br>
<%= f.text_area :description %>
</p>
<p>
Exits:
<br/>
<% #locations.each do |e| %>
<%= f.label :locations %>
<%= f.check_box :locations %>
<% end %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
#locations is all of the available locations to set up as an "exit". I'm trying to create an array of locations inside of the new location using checkboxes to check whether or not they should be set as "exits", but not really sure how to proceed since i'm just teaching myself and it's day one.
I'm also wondering how to set up the "exits" in the Location model. Right now i have:
class Location < ActiveRecord::Base
has_many :locations
validates :name, presence: true, length: { minimum: 1 }
validates :description, presence: true
end
created with:
class CreateLocations < ActiveRecord::Migration
def change
create_table :locations do |t|
t.string :name
t.text :description
t.references :location, index: true, foreign_key: true
t.timestamps null: false
end
end
end
But i would like to have them referenced as "exits" not "locations" (ie Location.exits instead of Location.locations).
UPDATE
I've updated the form to use the collection_check_boxes helper
<%= f.collection_check_boxes(:exit_ids, #locations, :id, :name) do |cb| %>
<%= cb.label %> <%= cb.check_box %> <br/>
<% end %>
So I have this in the create action now
def create
#location = Location.new(location_params)
if #location.save
params[:location][:exit_ids].each do |e|
if e.to_i > 0
tempLocation = Location.find(e.to_i)
#location.allowExitTo(tempLocation)
end
end
redirect_to #location
else
render 'new'
end
end
Which goes allows exits through:
def allowExitTo(other_location)
exit_locations.create(to_id: other_location.id)
end
creating an exit relationship with:
class Exit < ActiveRecord::Base
belongs_to :from, class_name: 'Location'
belongs_to :to, class_name: 'Location'
validates :from_id, presence: true
validates :to_id, presence: true
end
Hope I'm on the right track. It seems to work so I guess so.
Edit: Sorry, I must have had a brain-fart or something. You're not doing a simple has-many and belongs-to relationship, you want a has-many-and-belongs-to-many relationship. That's more complicated than I know how to explain. But this answer explained it very well: Many-to-many relationship with the same model in rails?
You can get Location#exits instead of Location#locations by changing the name of the has_many relation like this:
class Location < ActiveRecord::Base
# has_many :locations Instead of this...
has_many :exits, :class_name => 'Location' # ...Do this
validates :name, presence: true, length: { minimum: 1 }
validates :description, presence: true
end
This is called a self-join. You're associating a model with itself.
Keep in mind that this will make Location#locations unavailable.
Then in your form you would do something like:
<% #locations.each do |e| %>
<%= f.label :exit %>
<%= f.check_box :exit %>
<% end %>
The Ruby on Rails site has a nice guide about associations, includeing self-joins like what you're asking about: http://guides.rubyonrails.org/association_basics.html#self-joins
If you like RailsCasts: http://railscasts.com/episodes/163-self-referential-association

using a validation with has_many_through

I want to set up a validation so that people can't submit a post unless they click on a category for that post and also to make sure that they can chose only one of the categorys for that post so the post can have only one category. Here are the modles
class Categorization < ActiveRecord::Base
belongs_to :post
belongs_to :category
end
class Category < ActiveRecord::Base
has_many :categorizations
has_many :posts, :through => :categorizations
end
class Comment < ActiveRecord::Base
belongs_to :user
validates :content, presence: true,
length: { minimum: 5 }
end
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
has_many :categorizations
has_many :categories, :through => :categorizations
validates :title, :content, presence: true,
length: { minimum: 5, maximum: 140 }
end
also here is my form:
<%= form_for #post, :html => {:multipart => true} do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation" class="animated tada">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.file_field :image %>
</div>
<div class="field">
<%= f.label :content %><br>
<%= f.text_area :content %>
</div>
<%= hidden_field_tag "post[category_ids][]", nil%>
<% Category.all.each do |category| %><br>
<%= check_box_tag "post[category_ids][]", category.id, #post.category_ids.include?(category.id), id: dom_id(category)%>
<%= label_tag dom_id(category), category.name %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
</div>
do any of you know what I would need to put in to make my form come back with a message saying need to select category or can pick only one category?
We've done a similar thing with has_many :through
Validating On The Join Model
Our solution was to use accepts_nested_attributes_for, and validate on the join model. This could be seen as quite inefficient, but works well for us:
#app/models/message.rb
Class Message < ActiveRecord::Base
validates :title, :body,
:presence => { :message => "Needs A Value!" }
accepts_nested_attributes_for :message_subscribers, :allow_destroy => true
end
#app/models/message_subscriber.rb
Class MessageSubscriber < ActiveRecord::Base
#Validations
validates :subscriber_id,
:presence => { :message => "Your Message Needs Subscribers!" }
end
This returns an error if you don't have any subscriber_id's selected
Your Code
For you, I'd be tempted to do this:
class Categorization < ActiveRecord::Base
belongs_to :post
belongs_to :category
#Validation
validates :subscriber_id, :presence => { :message => "You need to select a category!" }
end
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
has_many :categorizations
has_many :categories, :through => :categorizations
#Validation
validates :title, :content, presence: true,
length: { minimum: 5, maximum: 140 }
end
I was going to include accepts_nested_attributes_for for you, but I realized it would be an inconvenient way to do something you're doing already. In light of this, I believe you may be best suited just performing the validations in your join model, however if it does not work, we'll add the accepts_nested_attributes_for functionality

Edit form load error using Formtastic, STI, Polymorphic & ActiveAdmin

I am new to rails and using a combination of formtastic, activeadmin,sti and polymorphic associations to build a form
When I I can create a nested form with the address parent with no problem, but when i introduce STI and attempt to build_origin_address instead of build_address, that is when I get the error below when loading the edit view
NameError in Admin/leads#edit
Showing .../app/views/admin/leads/_form.erb where line #3 raised:
uninitialized constant Lead::OriginAddress
Models:
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
belongs_to :lead
validates :line1, :presence => true, :length => {:minimum => 2}
attr_accessible :line1, :line2, :city, :state, :zip, :country
end
class OriginAddress < Address
end
class DestinationAddress < Address
end
class Lead < ActiveRecord::Base
has_one :origin_address, :dependent => :destroy, :as => :addressable
accepts_nested_attributes_for :origin_address, :allow_destroy => true
end
partial used in edit view:
<%= semantic_form_for [:admin, #lead] do |f| %>
<% #lead.build_origin_address unless #lead.origin_address %>
<%= f.inputs :name => "Lead Info" do %>
<%= f.input :first_name %>
<%= f.input :last_name %>
<% end %>
<%= f.semantic_fields_for :origin_address do |origin| %>
<%= origin.inputs :name => "Origin Address" do %>
<%= origin.input :line1 %>
....
<% end %>
<% end %>
<%= f.buttons do %>
<%= f.commit_button %>
<% end %>
<% end %>
I think you must define #lead before your form.

Using fields from an association (has_one) model with formtastic in rails

I searched and tried a lot, but I can't accomplish it as I want.. so here's my problem.
My models are:
class User < ActiveRecord::Base
has_one :profile
accepts_nested_attributes_for :profile
end
class Profile < ActiveRecord::Base
attr_accessible :user_id, :form, :title, :name, :surname, :street, :housenumber, :zipcode, :place, :phone, :mobile, :fax, :url
belongs_to :user
end
In my view:
<% semantic_form_for #user do |form| %>
<%= form.inputs :login, :email, :password%>
<% form.semantic_fields_for :profile do |profile| %>
<%= profile.inputs %>
<% end %>
<%= form.buttons %>
<% end %>
My problem is that when I edit a person then it shows me the data on the profile. I would, that the fields from the profile even when creating a user are displayed.
Thanks a lot!
You should add in your view before your form.semantic_fields_for:
<% #user.build_profile unless #user.profile %>
You could do it as well in your controller new after that you create your User object.

Resources