How to Set Up These Crud Controller Actions for Has_Many_Polymorphs and an Error

many to many relationship crud

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.

STI routing error

You can organize your controller better to avoid this issue altogether. See below

routes.rb

resources :kids 
resources :parents

This would directly give you named path:

edit_kid_path(kid_id) 
edit_parent_path(parent_id)

kids_controller.rb

class KidsController < ApplicationController
def update
end
end

parents_controller.rb

class ParentsController < ApplicationController
def update
end
end

If you want to share controller behavior, You can potentially do

class KidsController < UsersController
end

class ParentsController < UsersController
end

and put the common actions in users_controller.rb and override them in the child controllers.

The decision on what model relationships to use should be independent of how you structure your controllers. Controllers and routing is one area of consideration. Modeling data is entirely separately consideration. And declaring resources are just shortcuts for some matching routes.

If you are not going to use users#update etc, declaring resources :users is unnecessary as you are not using any of the routes that declaration provides.

MVC: How to work with entities with many child entities?

If you wish to use the kinds of paths you provided in your example, then it sounds like you should learn how to use the Routing engine in .NET 3.5. You should be able to use the kinds of urls you need, but you will need to create several custom routes and probably a custom route handler to accomplish it. The Routing engine in .NET 3.5 is very flexible and was not designed specifically for MVC...its actually very generic and can provide a very broad, probably unlimited range of url rewriting.

Its a bit late where I live, so the example I was trying to write just isn't forming. :P Suffice to say, a custom route handler and some new route mappings should get you where you need to be.

EDIT: This may be of help:

http://codingcockerel.co.uk/2008/05/26/custom-routing-for-asp-net-mvc/

EDIT 2:
I left out controllers before. The routing just gets you the ability to use the kinds of URLs you want. And thats a good thing...the kinds of URL's you proposed will provide a better SEO experience long-term. As for organizing your controllers, I recommend keeping it simple:

/Controllers/CarsController.cs
/Controllers/PartsController.cs
/Controllers/EmployeesController.cs
/Controllers/InventoryController.cs

Your routes would match your url patterns, and turn them into a proper route to your controller, taking the ID's and matching them to the parameters of your actions.

EDIT 3:

So, now that I understand your question more fully, I hope I can answer it better. Generally speaking, I think controllers should map 1:1 with your entities. If you have a GeneralPart, then you should have a controller dedicated to managing general parts. If you have CarPart, then you should have a controller dedicated to managing car parts. If CarParts are GeneralParts, and they can behave like GeneralParts in some cases, then it is probably best to have those management aspects on the GeneralPartsController, unless that management deals with any special attributes of a CarPart...in which case management should be delegated to CarPartsController. It is kind of elegant how polymorphism plays into controller organization, and how the "is a" relationship allows you to reuse controllers to manage multiple types.

To be honest, you have a fairly complex scenario I havn't directly encountered in my time working with ASP.NET MVC. I try to avoid such scenarios as much as possible, because they give rise to complicated questions like this that tend to be subjective in their answers. Ultimately, you should organize your controllers in a way that makes logical sense to how they are used, how they map to your entities, and how well they organize the behavior you are interested in exposing. Sometimes, it isn't logical to map all of your controllers to a single entity. Sometimes you need to have a "composite" controller that deals with actions that operate on multiple entities at once, or graphs of entities. In these cases, its probably best to have controllers dedicated to those particular behavioral groups, rather than trying to find one entity-specific controller that "sorta fits".

Comments on multiple models

You don't want to specify each type of object that can hold Comment objects. That creates a headache of if-elsif-else blocks all over the place. Instead, you want things to be Commentable, and they all will have .comments on them.

This is called a polymorphic association in Active Record. So you would have your models something like:

class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end

class Post < ActiveRecord::Base
has_many :comments, as: :commentable
end

class Book < ActiveRecord::Base
has_many :comments, as: :commentable
end

And modify your database accordingly, it's all in the linked article. Now when you build a Comment object for a form, it will have pre-populated a commentable_id and commentable_type, which you can toss in hidden fields. Now it doesn't matter what the Comment is associated with, you always treat it the same.

I'd leave User as a separate association, since it's not really the same idea.

Rails 4 nested forms link_to edit not working in loop

I think the issue's actually a little trickier, because edit_todo_list_path(list) seems to throw the same error.

What's going on is that the @todo_lists variable (first an array of persisted lists) is altered when you run @todo_list = current_user.todo_lists.new. That command actually adds a new (unpersisted) list to the end of the @todo_lists array (seems like buggy behavior to me, but it's happened to me before), so that when your view is looping through them, the last one has no id, and a path cannot be created for it.

The solution is (I think) to make that variable after you've used the @todo_lists variable.

Take @todo_list out of the controller, and where you use it in the view, instead do current_user.todo_lists.build. That should instantiate a new list without changing the @todo_lists variable.



Related Topics



Leave a reply



Submit