Search code examples
ruby-on-railsmany-to-manycruderd

many to many relationship crud


I have users and each user has addresses and each address belong to a case

how can i add the result of case new to show in case show

in case new

   <%= form_for @case,:url => {:action => :create, :id => @user.id} do |f| %>
     Address:<br>
     <%= f.select :address_ids, options_for_select(@user.addresses.all.pluck(:name,:id)) %><br><br>
  <% end %>

in case show (this gives me all the addresses for the user not the address that I choose from case new.html.erb

  <strong>Address: </strong><% @user.addresses.each do |s| %>
    <%= s.name %>
  <% end %> 

case model

class Case < ActiveRecord::Base
  belongs_to :user
  has_many :addresses, dependent: :destroy

in user model

class User < ActiveRecord::Base
  has_many :cases
  has_many :addresses, dependent: :destroy

in address model

class Address < ActiveRecord::Base
  belongs_to :user
  belongs_to :case
end

Solution

  • It retrieves all the addresses because you query the address from the user himself not from the case object that you supposedly created from the new view.

    So, first, I would add create action to create the case first (to which we will assign the chosen address):

    def create
      # @user can be retrieved from the passed id in the url
      @user = User.last
      @case = Case.create(user: @user)
      @case.addresses << Address.where(id: params.require(:case)[:address_ids])
    end
    

    and change your controller show action to something like this:

    def show
      # @case can be retrieved any way you like, this is just an example
      @case = Case.last
    end
    

    and make your show view like this:

    <strong>Address: </strong>
    <% @case.addresses.each do |s| %>
      <%= s.name %>
    <% end %>
    

    This would solve your issue.


    Some notes to consider later:

    1. So far this new view only allows you to choose one address (not multiple) so it won't be needed to use has_many association (if you want to use it, then you have to figure out a way to choose multiple addresses).
    2. The @user.id can be passed through the url instead of explicitly defining it in the form. Look at Nested Resources for more info.
    3. The url attribute in the form can be replaced by _path helpers, the same above link would give you a hint as well.
    4. Try to stick to Ruby styling, like indentation and naming. For example, the |s| is not descriptive .. would be better to be named address or addr
    5. As I can see, you can try using through instead of duplicating the associations. E.g. Case belongs_to User & Case has_many Addresses, so User can has_many cases & User has_many addresses, through: :cases .. like this you can retrieve user's addresses specific to that case. Like this, when you try to create an address and retrieve it from @user.addresses, you will get an error because an address already needs a user and a case to be created in the first place, so the associations are not set perfectly and as a result you will need workarounds to prevent these errors.