Devise - Nested Attributes - Customer --> Customer_addresses --> Address - ruby-on-rails-4

I have been trying to create a relationship like the database listed below, using devise to create the Customer table. I have created migrations for the other tables using the ID ing though table-names and ID. My models look like the below. I know I have gone overboard with the has_many relationships, but I have been trying this all day.
Can anyone help or show the correct way to set up this so that I can create, edit and update addresses on the user. I have managed success with simple nested attributes say Customer/ Direct to address but when I place the table in the middle I just cant get the address attributes to show or update.
I guess there is a more complex edit, create , destroy method that needs to be implemented also.
I'm also getting lost with how to allow strong params on this type of nesting as most examples i can find only have it connected to tables that hold the user_id in them and not one that is connected through another table.
cheers in advance for the guidance.
DataModel image here
Tables
customers / Devise table defaults
customer_addresses
id
address_id
address_type_id
customer_id
addresses
id
address xzy Marua Road
other details / Front house
address_type
id
address_type / Home , Business etc
address_type_description / Where you live etc
class Customer < ActiveRecord::Base
has_many :customer_addresses
has_many :addresses
has_many :address_types
accepts_nested_attributes_for :customer_addresses
accepts_nested_attributes_for :address_types
accepts_nested_attributes_for :addresses
end
class UserAddress < ActiveRecord::Base
has_many :customer
has_many :address_types
has_many :addresses
end
class AddressType < ActiveRecord::Base
belongs_to :customer_address
end
class Address < ActiveRecord::Base
belongs_to :user_address
end
<div class="field">
<%= f.fields_for :user_addresses do |ff| %>
<div>
<%= ff.label :address_id %><br />
<%= ff.text_field :address_id %>
<%= ff.fields_for :address do |fff| %>
<%= fff.label :address %><br />
<%= fff.text_field :address %>
<% end %>
<% end %>
</div>
</div>
user controller params
def user_params
params.require(:user).permit(:id, :username, :first_name, :last_name, :email, :password, :password_confirmation,
user_address_attributes:[:user_is, :address_id, :address_type_id],
addresses_attributes:[:id, :address, :other_address_details ],
address_type_attributes:[ :id, :address_type])
end

The associations you defined should have been like the following
class Customer
has_many :customer_addresses
has_many :addresses, :through => :customer_addresses
has_many :address_types, :through => :customer_addresses
end
class Address
has_many :customer_addresses
has_many :customers, :through => :customer_addresses
has_many :address_types, :through => :customer_addresses
end
class AddressType
has_many :customer_addresses
has_many :customers, :through => :customer_addresses
has_many :addresses, :through => :customer_addresses
end
class CustomerAddress
belongs_to :customer
belongs_to :address
belongs_to :address_type
end

class Customer < ActiveRecord::Base
has_many :customer_addresses
accepts_nested_attributes_for :customer_addresses
end
class AddressType
has_many :customer_addresses
end
class CustomerAddress
belongs_to :address_type
belongs_to :customer
belongs_to :address
accepts_nested_attributes_for :address
after_initialize :add_address, unless: 'address.present?'
def add_address
self.build_address
end
end

Related

How to raise error when validation on nested attributes fails

Here are 2 models: customer and address. A customer has_one address.
class Customer < ActiveRecord::Base
has_one :address
accepted_nested_attributes_for :address, :allow_destroy => true
end
class Address < ActiveRecord::Base
belongs_to :customer
validates :add_line, :presence => true
end
<% simple_form_for #customer do |f| %>
.....
<%=f.simple_fields_for :address do |builder| %>
<%=render ('address', f: builder) %>
<% end %>
<%end %>
address view
<%=f.input :add_line %>
address is nested attribute in customer. The problem we are having is that if address is modified wrongly (ex, a nil add_line) within customer view, there is no error (#customer.update_attributes in customer controller) popping up. Is there a way setting up the nested attributes in such a way nil add_line will fail the update?
Two things caught my eye with your original post:
One,remember that you need a belongs_to :customer in the Address model.
Two, you need to add a validation in the Customer model
class Customer < ActiveRecord::Base
has_one :address
accepted_nested_attributes_for :address, allow_destroy: true, reject_if: :address_invalid
private
def address_invalid(attributes)
# add custom validation code here ...
end
end

(rails4)how can i validate an user cannot book a route with overlapping time?

i have an user model:
class User < ActiveRecord::Base
has_secure_password
attr_accessible :email, :password, :password_confirmation, :cardnumber, :registration
validates_uniqueness_of :email
has_many :bookings
has_many :routes, :through => :bookings
end
then a route model :
class Route < ActiveRecord::Base
attr_accessible :id, :departurecity, :arrivalcity, :departuretime, :arrivaltime, :train_id
has_many :stops
belongs_to :train
has_many :bookings
has_many :users, :through => :bookings
end
an finally bookink model:
class Booking < ActiveRecord::Base
attr_accessible :route_id, :user_id, :dateb, :hourb, :citydeparture, :cityarrival, :id, :tripclass
belongs_to :user
belongs_to :route
The question is how can I make a method on booking model which an user cannot book a train route with overlap time on another booked train route by the same user?

ActiveAdmin has_many through relationship not updating param Rails

I'm working through creating a has_many: through relationship in active admin. Here are the models as they stand:
class Category < ActiveRecord::Base
has_many :subcategories
end
class Subcategory < ActiveRecord::Base
has_many :product_in_subcategories
has_many :products, through: :product_in_subcategories
accepts_nested_attributes_for :product_in_subcategories, :allow_destroy => true
belongs_to :category
end
class Product < ActiveRecord::Base
has_many :product_in_subcategories
has_many :subcategories, through: :product_in_subcategories
accepts_nested_attributes_for :product_in_subcategories, :allow_destroy => true
end
class ProductInSubcategory < ActiveRecord::Base
belongs_to :product
belongs_to :subcategory
end
In ActiveAdmin I have the permit_params and form like so:
ActiveAdmin.register Product do
# note some params that are product only have been removed for simplicity
permit_params :name, subcategory_id:[:id], product_in_subcategories_attributes: [:id, :subcategory_id, :product_id, :_create, :_update]
form do |f|
f.inputs
f.has_many :product_in_subcategories do |s|
s.input :subcategory_id, :as => :check_boxes, :collection => Subcategory.all
end
f.actions
end
end
The form populates as should, and will save everything except for the subcategory_id. If I enter into the DB a proper subcategory_id the box will show checked on edit.
The messages when saving give:
Unpermitted parameters: subcategory_id
However, it appears it is trying to submit this with the product, for which there isn't a subcategory_id. Any ideas on what I am doing incorrectly here? This is driving me nuts and I've read everything I can find. I'd really like to understand what I'm doing wrong. Thanks.
After much time spent on this one, I couldn't find a suitable solution except for this one, which is actually very nice. It in fact is not much different from my envisioned solution:
The only changes to the above code were made in ActiveAdmin:
ActiveAdmin.register Product do
# note some params that are product only have been removed for simplicity
permit_params :name, product_in_subcategories_attributes: [:id, :subcategory_id, :product_id, :_create, :_update]
form do |f|
f.inputs
f.has_many :product_in_subcategories do |s|
s.input :subcategory_id, :as => :select, :collection => Subcategory.all
end
f.actions
end
end
Very strange how this allows a select box with no issues, but it flips out over check boxes. Nonetheless, I'm happy with the solution.

how to specify has_many through vs has_many

So I'm trying to figure out how to specify between calling all instances of an object based on the has_many and has_many :through associations. I have users, groups and members. the member model is a pairing of groups and users. the groups also have a user_id in that model. so this will make more sense after you see the code:
user model
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :groups
has_many :groups, :through => :members
end
group model
class Group < ActiveRecord::Base
has_many :users, :through => :members
belongs_to :user
end
member model
class Member < ActiveRecord::Base
belongs_to :groups
belongs_to :users
end
Index View
<!--these are the groups I own (the group.user_id is my id) NEEDS EDITING-->
<% #groups.each do |group| %>
<%= link_to group.title, group_path(group) %>
<%= truncate group.desc %>
<% end %>
<!--I'm a member of these groups (connected through the member model) NEEDS EDITING'-->
<% current_user.groups.order(:created_at).each do |group| %>
<%= link_to group.title, group_path(group) %>
<%= truncate group.desc %>
<% end %>
I'm trying to figure out how to call the different types of associations users and groups in the Index View.
I want to get a list of all the groups that have me listed as admin (group.user_id) and then I want to get a separate list of all the groups that I'm a member of (through the member model).
I know I can query it with a find or where call. However, I was hoping there was a simple way like current_user.groups or something. anyway, thanks!
I would consider calling the 1:N relationship to groups another name. So you would end up with something like
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :owned_groups, class_name: 'Group'
has_many :groups, :through => :members
end
So the index view would look something like:
<% current_user.owned_groups.each do |group| %>
<%= link_to group.title, group_path(group) %>
<%= truncate group.desc %>
<% end %>
<% current_user.groups.order(:created_at).each do |group| %>
<%= link_to group.title, group_path(group) %>
<%= truncate group.desc %>
<% end %>

Rails mass assignment: extra brackets from where?

Assuming near-identical view, controller and models (except for names, obviously), how would you get this params output in your cli:
$ "project"=>{"genres_projects_attributes"=>{"genre_id"=>["1"]}
versus this params output:
$"user"=>{"production_media_users_attributes"=>[{"production_medium_id"=>["1"]}]}
Note the additional brackets [] in the second line. The first line works. The second line does not. There is no error message.
source code below, but looks identical to me:
controller
def user_params
params.fetch(:user, {}).permit(:id, production_media_users_attributes: [:id, :user_id, {production_medium_id: []}])
end
def project_params
params.fetch(:project, {}).permit(:id, genres_projects_attributes: [:id, :project_id, {genre_id: []}])
end
models
class User < ActiveRecord::Base
has_many :production_media, through: :production_media_users
has_many :production_media_users
accepts_nested_attributes_for :production_media_users
end
class ProductionMedium < ActiveRecord::Base
has_many :users, through: :production_media_users
has_many :production_media_users
end
class Project < ActiveRecord::Base
has_many :genres, through: :genres_projects
has_many :genres_projects
accepts_nested_attributes_for :genres_projects
end
class Genre < ActiveRecord::Base
has_many :projects, through: :genres_projects
has_many :genres_projects
end
views
<%= select_tag 'user[production_media_users_attributes][][production_medium_id][]', options_for_select(ProductionMedium.order(:id).collect{|g| [g.name, g.id]}), { include_hidden: true, multiple: true, required: true, placeholder: 'Choose One or More', class: 'form-control menu-select2'} %>
<%= select_tag 'project[genres_projects_attributes][][genre_id][]', options_for_select(Genre.order(:id).collect{|g| [g.name, g.id]}), { include_hidden: true, multiple: true, required: true, placeholder: 'Choose One or More', class: 'form-control menu-select2'} %>
theres an extra colon on production_media_users_attributes, is that it?
params.fetch(:user, {}).permit(:id, :production_media_users_attributes: