using a validation with has_many_through - ruby-on-rails

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

Related

simple_forms with two classes

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

Creating an object with a nested form - how to pass params to controller

I'm really struggling with how to make a form create an object, and two sub-objects. My Guide has_one City_obj and has_one Country_obj.
guide.rb
class Guide < ActiveRecord::Base
has_one :city_obj, dependent: :destroy
has_one :country_obj, dependent: :destroy
belongs_to :user
has_many :guide_pics, dependent: :destroy
accepts_nested_attributes_for :city_obj, :country_obj
end
city_obj.rb
class CityObj < ActiveRecord::Base
belongs_to :guide
belongs_to :country_obj
end
country_obj.rb
class CountryObj < ActiveRecord::Base
belongs_to :guides
has_many :city_obj, dependent: :destroy
end
new.html
<%= form_for(#guide) do |f| %>
<%= render 'new_form_part', f: f, field: 'name', label: 'name', type: 'text_field',
<%= f.fields_for :country_obj, #guide.country_obj do |p| %>
<%= f.text_field :name, class: 'form-control' %>
<% end %>
<%= f.fields_for :city_obj, #guide.city_obj do |p| %>
<%= f.text_field :name, class: 'form-control' %>
<% end %>
<% end %>
In my controller create method, I get
params[:guide] = {"name"="whatever is submitted for city"}
That's because the partial that sets :name is being overwritten by the text_fields below. How can I get them to pass params[:guide][:city_obj][:name] and params[:guide][:country_obj][:name]?
UPDATE: There is a typo. I should be using p.text_field, not f.text_field

Has Many Through. How to get the access?

Here is my models:
class Item < ActiveRecord::Base
has_many :price_group_lines
has_many :price_groups, through: :price_group_lines
attr_accessible :item_name, :item_id
validates :item_name, presence: true
def to_label
"#{item_name}"
end
end
class PriceGroup < ActiveRecord::Base
has_many :customers
has_many :price_group_lines
has_many :items, through: :price_group_lines
attr_accessible :price_group_name
validates :price_group_name, presence: true
def to_label
"#{price_group_name}"
end
end
class PriceGroupLine < ActiveRecord::Base
belongs_to :item
belongs_to :price_group
attr_accessible :item_id, :price_group_id, :price, :item, :price_group
validates :price, :item_id, :price_group_id, presence: true
end
View (show.html.erb) for Price Group controller
<h1> PRICE GROUP </h1>
<p> <%= #pg.price_group_name %> </p> <br>
<% #pg.items.each do |i|%>
<%= i.item_name %>
<% end %>
<br>
<%= link_to "PRICE GROUP List", price_groups_path %>
So, I have the access to item_name in show.html.erb, but i don't know how to get the access to "price" attribute in PriceGroupLine model. Something, like
i.items.price not working. Please, help!
Problem is because you have association of price, better said prices.
Your variable i is already item just call price_group_lines on it and you will get association on which you can call each and get each price.
<% #pg.items.each do |i|%>
<%= i.item_name %> # will display item name
<% i.price_group_lines.each do |pgl| %>
<%= pgl.price %> # will display price
<% end %>
<% end %>

Rails uninitialized constant for an association

So there is a plethora of questions about the "uninitialized constant" error, and it's almost always due to an incorrectly specified association (e.g. plural model names instead of singular, incorrectly writing your association inside the model, etc). My models and form look spotless, so maybe this is something new (or I'm blind)?
A "user" has one "move". A "move" has many "neighborhood_preferences", and through this, many "neighborhoods".
Models:
class User < ActiveRecord::Base
has_one :move
accepts_nested_attributes_for :move, allow_destroy: true
end
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
class Neighborhood < ActiveRecord::Base
belongs_to :city
has_many :neighborhood_preferences
has_many :moves, through: :neighborhood_preferences
end
View:
<%= simple_form_for(#user, :html => { class: :form } ) do |u| %>
<%= u.fields_for :move do |m| %>
<div>
<%= m.label :start_date %>
<%= m.date_field :start_date %>
</div>
<div>
<%= m.label :end_date %>
<%= m.date_field :end_date %>
</div>
<div>
<%= m.label :min_price %>
<%= m.text_field :min_price %>
</div>
<div>
<%= m.label :max_price %>
<%= m.text_field :max_price %>
</div>
<%= m.association :neighborhood_preferences %>
<% end %>
<%= u.submit "Save Changes" %>
<% end %>
There is a typo in class name NeighbhoodPreference.

rails: Updating a record nested two join tables deep

I have a problem that's really confusing me.
I have four models, a Workout model, an Exercise model, a workout_exercise join model, and a workout_exercise_set model.
I can add exercises to workouts through the workout_exercises join table. Now I'm trying to add sets to exercises in workouts, which is what the workout_exercises_sets table is for.
Here's an example.
Workout
Exercise 1
Set 1
Set 2
Set 3
Exercise 2
Set 1
Set 2
Set 3
Exercise 3
etc.
In workouts/edit.html.erb I have a form where I can see all the exercises in the workout, and edit the number of sets by using form_for and fields_for, but when I try to update an exercise or the entire workout I get a MassAssignmentSecurity::Error in WorkoutsController#update that says Can't mass-assign protected attributes: workout_exercise_sets. I can't figure out how to get past this. I know I'm editing a workout, but I'm not trying to write to a field called workout_exercise_sets, so I'm really confused here. I really appreciate any guidance. All relevant code is below.
workout/edit.html.erb:
<%= form_for(#workout) do |f| %>
<%= f.label :name %><br />
<%= f.text_field :name %><br />
<%= f.label :description %><br>
<%= f.text_area :description %></br>
<%= f.fields_for :workout_exercises do |s| %>
<%= s.object.exercise.name %></b>
<%= s.fields_for :workout_exercise_sets do |set| %>
<%= set.label :set_number %>:
<%= set.number_field :set_number %>
<%= set.label :reps %>:
<%= set.number_field :repetitions %>
<%= set.label :rest_time %>(seconds):
<%= set.number_field :rest_time %>
<%= set.submit %>
<% end %>
<%= s.hidden_field :_destroy %>
<%= link_to "Remove exercise?", '#', class: "remove_fields" %>
<% end %>
<%= f.submit %>
<% end %>
Here is the workout model:
class Workout < ActiveRecord::Base
attr_accessible :name, :exercises_attributes, :workout_exercises_attributes, :exercise_order, :description
has_many :workout_exercises, dependent: :destroy, :order => "exercise_order DESC"
has_many :exercises, through: :workout_exercises
accepts_nested_attributes_for :exercises
accepts_nested_attributes_for :workout_exercises, allow_destroy: :true
end
Here is the exercise model:
class Exercise < ActiveRecord::Base
attr_accessible :name, :description
has_many :workout_exercises
has_many :workouts, through: :workout_exercises
validates :name, uniqueness: :true, presence: :true
validates :description, uniqueness: :true, presence: :true
end
Here is the workout_exercise model:
class WorkoutExercise < ActiveRecord::Base
attr_accessible :exercise_id, :workout_id
belongs_to :exercise
belongs_to :workout
has_many :workout_exercise_sets, dependent: :destroy
accepts_nested_attributes_for :workout_exercise_sets, allow_destroy: :true
end
and finally, here is the workout_exercise_sets model:
class WorkoutExerciseSet < ActiveRecord::Base
attr_accessible :repetitions, :rest_time, :set_number, :workout_exercise_id
belongs_to :workout_exercise
end
And for good measure, here is a diagram of the DB:
I think in your workout_excercise.rb file, you should add :workout_exercise_sets_attributes to your attr_accessible list.
class WorkoutExercise < ActiveRecord::Base
attr_accessible :exercise_id, :workout_id, :workout_exercise_sets_attributes
belongs_to :exercise
belongs_to :workout
has_many :workout_exercise_sets, dependent: :destroy
accepts_nested_attributes_for :workout_exercise_sets, allow_destroy: :true
end

Resources