I have a Person model which has many Animal models as pets. Dog is an Animal with a "favorite bone" field, and Cat is an Animal with a "likes catnip?" field and a "favorite fish" field.
#models
class Person(db.model):
pass
class Animal(db.model):
models.ForeignKey(Person) #owner
name = CharField()
class Dog(Animal):
favorite_bone = CharField()
class Cat(Animal):
favorite_fish = CharField()
likes_catnip = BooleanField()
I would like to inline edit all of a Persons pets, in the Person admin form however, I've read that Django inline admin forms don't support polymorphic inline forms[1], in that, you will only get the parent class fields (e.g. not the favorite_bone or favorite_fish and likes_catnip fields.
Where does this problem come from?
What changes could be made to the framework to accommodate this?
If these changes should not be made, why not?
[1] http://www.mail-archive.com/django-users#googlegroups.com/msg66410.html
(This is an old question, but I thought I'd add an answer in case it is still useful. I've been working on a similar question recently.)
I believe it would be challenging to change Django form-generation to do what you want. The reason is that the inline formset uses a single class/form for all rows of the inline -- there are no configuration options that are evaluated per-row of the inline form. I have convinced myself of this by reading the code itself --- look for "inline" and "formset" in django.contrib.admin.options.py, especially lines 1039-1047 (version 1.5.1). This is also the reason why you can't have some fields read-only in existing items and changeable in new items (see this SO question, for example).
The workarounds found for the readonly case have involved a custom widget that produces the desired behavior such as this one. That still won't directly support polymorphism, however. I think you would need to end up mapping your divergent types back to a common ancestor (e.g. have all pet classes able to return a dict of their unique attributes and values), and then create a single custom widget that renders out the polymorphic part for you. You'd then have to map the values back on save.
This might be more challenging than it is worth, and may lead back to the suggestion in the other answer to not use admin for this :-)
may have a look here.
but i think the modeladmin is currently not able todo such things.
you are able to create a custom edit view for your model...
there is almost everything possible.
It may be possible to do this with Generic Relations.
Related
Disclaimer: I really spent time thinking about names of models and variables. If you also do, this question is for you.
I have a Rails project which contains two models: User and Project.
They are connected by the model ProjectsUser, which is a connection model in a many-to-many relationship. This model also holds the role of a user in the given project, along with other attributes such as tier and departments. So this is a has_many :through relationship.
Given this scenario, here is everything that always bothered me on all my rails projects since I started developing on it:
Should I use a ProjectsUserController or better add the relevant actions on UserController and ProjectController? At some point, I want to assign users to a project, or even changing the role of a user in a given project. Is it a better practice to leave those actions on the connection controller, or use the model controllers?
Should I write a method to get the role of a user for a given project? This is basically if I should have a method User#role_for(project) or not. Since this method basically is getting the information from the projects_user object it could make more sense to always let this explicity on the code, since most of the times I'll have the project and the user, but not the projects_user. Is this line of thinking correct, or maybe the problem is that I'm should have more project_user on my code than I really do? Are there good caveats for this?
Should I try to rename my table to a non-standard name if it is not obvious? Ok, I got that if I have the models User and NewsSite I should use has_many :subscriptions, but the thing is that naming those models in real life cases are usually harder, by my experience. When the name ends up not being that obvious (for exemple, in my case, maybe project_participation as #wonderingtomato suggested) is for the best, or in those cases it is better to fall back to the ProjectsUser approach?
One extra cookie for pointing beautiful open source Rails code, or by book indications that might help with my kind of questions.
I would use a specific controller. Even if now the interaction sounds simple, you can't know if in the future you'll need to add more advanced features.
I've been handling these kind of relationships in several projects, and using a controller for the join model has always paid off.
You can structure it this way, for example:
index should expect a params[:project_id], so that you can display only the index of users for a specific project.
create is where you add new users, that is where you create new join models.
update is to modify a value on an existing join model, for example when you want to update the role of a user in a project.
destroy is where you remove users from the project, that is where you delete the corresponding join models.
You might not need a show and edit actions, if you decide to manage everything in the index view.
Also, I'd suggest to choose a different name. Rails relies heavily on naming conventions, and projects_users is the default name for the join_table you would use with a has_and_belongs_to_many association. In theory you can use it for an independent model (and a has_many through:), but it's not immediately clear and you might break something. In addiction, it will confuse the hell out of any new programmer that could join the project in the future (personal experience).
What about calling the model something like project_participation?
If you haven't built a lot of functionality yet, and don't have yet that table in production, changing it now will save you a lot of headaches in the future.
update
1) I stand by what I said earlier: your join model is a full fledged record, it holds state, can be fetched, modified (by the user) and destroyed.
A dedicated controller is the way to go. Also, this controller should handle all the operations that modify the join model, that is that alter its properties.
2) You can define User#role_for(project), just remember that it should properly handle the situation where the user is not participating to the project.
You can also make it explicit with something like:
#user.project_participations.where(project_id: #project.id).first.try(:role)
# or...
ProjectParticipation.find_by(project_id: #project.id, user_id: #user.id).try(:role)
But I'd say that encapsulating this logic in a method (on one of the two models) would be better.
3) You are already using a non standard name for your table. What I mean is that it's the default name for a different kind of association (has_and_belongs_to_many), not the one you are using (has_many through:).
Ask yourself this: is the table backing an actual model? If yes, that model represents something in the real world, and thus should have an appropriate name. If, on the other hand, the table is not backing a model (e.g. it's a join table), then you should combine the names of the tables (models) it's joining.
In my mind, REST doesn't always have to map directly to DB records. A conceptual resource here is the association of Projects to Users. Implementation would be different depending on your persistence layer, but a RESTful API would be standard.
Convention over Configuration in Rails is a great helper, but it isn't necessarily applicable to every case 100% of the way through the stack. There doesn't need to be a 1-to-1 mapping between controllers, models, and their respective names. At the app-level, particularly, I want my routes/controllers to represent the public view of the API, not the internal implementation details of the persistence and domain layers.
You might have a UserProjectsController which you can perform CRUD on to add/remove project associations to users, and it will do the appropriate record manipulation without being overly bound to the DB implementation. Note the naming, where the route might be /user/:id/projects, so it's clear you are manipulating not Users or Projects, but their associations.
I think thinking about this sort of thing (both before and after the fact) is what leads to better designs.
I too start with the model and think about the application structurally. The next step in my oppinion is to build the user interface to make sense based on what makes it easy and useful for the user (spending more effort on things that matter more). So if it makes sense for the user to separately edit the ProjectsUser objects then the ProjectsUsersController is the way to go. More likely editing the join model objects as part of the Project (or User depending on the structure of you app) will be a better fit for the user. In that case using a nested form and editing via the controller (and model) that's the main model referenced by the form is better. The controller really lives to serve the UI, so decisions about it should be dependent on the UI.
Yes, if it makes your code simpler or more readable. If you use role more than once I suspect it will.
I would actually name that model something like Member, or ProjectMember (or Membership). It defines a relationship between a user and a project, so its name should reflect what relationship that is. In the occasions where such a name is too unwieldly or too hard to define then falling back to something like ProjectUser is reasonable (but not ProjectsUser). But I definitely like finding a more meaningful name when possible.
I'm reading "Rails AntiPatterns" at the moment, and one of the first patterns mentioned is the Single Responsibility Principle. At this point I've encountered SRP enough times to realize that it's a fundamental concept for beginners like me to understand, which is why it's so frustrating that it's not clicking yet.
The book gives an example of an Order class:
class Order < ActiveRecord::Base
def self.find_purchase
#...
end
def self.find_waiting_For_review
#...
end
def self.find_waiting_for_sign_off
#...
end
def self.advanced_search(fields, option = {})
#...
end
def self.simple_search
#...
end
def self.advanced_search
#...
end
def to_xml
#...
end
def to_json
#...
end
def to_csv
#...
end
def to_pdf
#...
end
end
To illustrate SRP, the book recommends extracting out the 4 instance methods into a separate OrderConverter class. This makes sense to me. But at the same time, this OrderConverter class could still have multiple reasons to change:
If the application no longer requires one of the 4 formats mentioned,
the corresponding method would have to be deleted.
If the application
needed to convert to other formats, more methods would need to be
implemented.
If the method used to convert Order instances to different formats is
changed (assuming they all use the same method with a different parameter
which corresponds to the format required).
Wouldn't it be even more "correct" to separate each of these methods into a separate converter class (i.e. PdfConverter, CsvConverter, XmlConverter, etc.)? That way, the only reason for each converter class to change would be if the conversion method itself changed. If a new format was needed, a new class could be created. And if an old format is no longer needed, the class could simply be deleted. And should the original Order model really be responsible for finding instances of itself? Couldn't you separate the 'find' methods into a separate 'OrderFinder' class?
I've read the SRP chapter of Sandi Metz's "Practical Object-Oriented Design In Ruby", and she recommends the following test to see if a class has a single responsibility:
How can you determine if the Gear class contains behavior that belongs somewhere
else? One way is to pretend that it's sentient and to interrogate it. If you
rephrase every one of its methods as a question, asking the question out to make
sense. For example, "Please Mr. Gear, what is your ratio?" seems perfectly
reasonable, while "Please Mr. Gear, what are your gear_inches?" is on shaky
ground, and "Please Mr. Gear, what is your tire(size)?" is just downright
ridiculous.
But taken to an extreme, if a model has more than one attribute (i.e. a car has a # of doors and a color) with corresponding attr_accessors, isn't this already a violation of SRP? Doesn't each new attribute add another possible reason for the class to change? Clearly the answer is not to separate each of these attributes into separate classes. So then where does one draw the line?
You write about the OrderConverter class but you didn't show the source of that class. I assume that this class contains methods to_xml, to_json, to_csv and to_pdf.
Wouldn't it be even more "correct" to separate each of these methods into a separate converter class (i.e. PdfConverter, CsvConverter, XmlConverter, etc.)?
Yes, it's propably a good idea to separate these methods to converter classes: each converter class will be responsible for only one format (one responsibility).
... if a model has more than one attribute (i.e. a car has a # of doors and a color) with corresponding attr_accessors, isn't this already a violation of SRP?
Nope, these attributes (like color, no of doors, ...) are not a set of responsibilities! The responsibility of Car class is describing a Car (holding an information about a car). Each instance of car will describe one car. If a car for example is a model class (let's say you want to store a cars in DB and one instance of car is one row in DB) then you have to change the Car class if you want to change a way of describing a car in your system.
But if a car will have defined for example a producer, and a producer will be described by name and address then I would extract the details of producer to other classes because this is a responsibility of describing a producer of a car and not a Car itself.
One more thing. The SRP is not a pattern. This is a Principle (first in SOLID). This term was introduced by Robert Cecil Martin. Here http://www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod you can find more information.
You seem to decide that extracting colour and number of doors into seperate classes is too far, which I'd disagree with. Indeed, if car is a very simple car class, maybe it is somewhat over the top. However, there are only a certain number of valid colours, only certain numbers of doors are valid. What if I want to be able to identify my car colour by any of a series of aliases?
CarColor seems like a perfectly valid class to me. It can store all the logic of what is and is not a valid color, provide aliases etc.
Consider an example I've dealt with recently concerning names in a series of places in different forms:
Database 1: Joan Smith
Right, I'll take the name, stick it in a String and put it in my person. No point making a fuss and wrapping one thing in it's own class.
Database 2: Smith, Joan
Ok, so I'll override the setter, check for this format and flip it if it's right.
Database 3: person: { title: Mrs, first: Joan, last: Smith }
Right, we'll just stick the title on the beginning, concatenate the last 2 together and then glue the whole thing into our damned string.
Database 4: foreign name that doesn't follow your structure and the whole concept of first, middle, last takes on a completely different meaning.
...turns out names are complicated.
This can all be nicely avoided by taking your supposedly simple structures and delegating to another class to handle what a name means, when are two names the same, how do we print them etc.
Prematurely wrapping all singleton values in their own classes can be somewhat overkill - but I've found that a bias towards wrapping when in doubt tends to serve me well later even if it feels silly at the time, especially when the value permeates through the rest of the code and so changing it later affects everything.
I am trying to use single table inheritance for some of my models. The base model is a Tournament, and I wish to extend this to create different types of tournaments. For instance, I might want to add a SingleEliminationTournament, or a DoubleEliminationTournament, both of which would inherit from Tournament. I have 2 questions, both of them somewhat related.
1) I would like the user to be able to create tournaments with a form, and to do this they would need to select one of the subclasses. Is there a way to get all of the subclasses and use them to populate a select box or something like that?
2) Since this information is going into a form, it would be nice to be able to validate the input into type. To do this, I would like to add a validation in the Tournament class that could check to make sure the Type was valid.
Obviously, I could hard code the values into the validation and the form, but I would not like to do that. Any help would be appreciated. Thanks!
TheModel.subclasses
would give you a list of types you need to include, but only if the models are loaded at runtime. They will always be loaded in production mode. You will have to load them manually in development mode.
You could create a directory with tournaments in them and load them with Dir.glob('app/tournaments/**/*_tournament.rb'). This gives you a nice listing all the tournament files you've specified. Because of convention, you can then infer the proper class name for each tournament.
Store this list of tournament names somewhere for reference in you validations and forms.
I'm not a Rails expert and I'm not sure if this can be considered clean, but for the validation part of your question, this worked for me:
Inside Tournament model:
def validate_type_implemented
klass = type.constantize rescue Object
raise "Given type not available." unless klass.class == Class and klass <= self.class
end
Suppose i have a class name Object, which has "Name" and "use" attributes. A second class named "Person" has an attribute called "how_many_objects_this_person_has". I'm trying to create a view that will look for a Person (i provide the id), see how many objects this person has, say N, and creates a form with N lines, one for each object, with fields for the two object's attributes. When the user clicks the submit button all objects must be saved, each one having an unique object id.
Any suggestion? I know it seems very simple, but i'm an starter. I looked for the answer for a whole week now and couldn't solve it myself.
Thanks a lot,
Gustavo
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2
I think you will find that for a decent user experience you will most probably wish to allow the user to add and remove records as they go along in addition to/instead of predetermining the number of records to add. The above railscasts show how to do this
Oh yeah! I used the same method in another part of my app. Didn't realize i could just do the same thing but without showing anything about the Person class.
By the way, there are two things to pay attention in that tutorial. You have to list the :objects_attributes in the attr_accessible (as said above). And the other is that there is a double html escape in the javascript code which makes the actual html to be rendered. Just look for some text in "h(text text text text)" and remove the "h()".
Thanks a lot!
Am I missing something fundamental to the principals of MVC or am I going mad?
If I have a view that displays a list of books and a list of authors, I have to create class that would have the list of Books and list of authors as properties. Right?
I would then strongly type the view to use this class.
Now I want to create a new page with the same listings but that also has a list of promotions. Do I need to create another class with a list of Books property, a list of authors property and a list of promotions property?
If I am creating classes for all the views I am creating a hell of a lot of extra work. Am I supposed to be creating strong typed partials for each of these? What if the layout differs each time?
Currently I have a BaseViewData class that is used by all the views as it contains some common properties. However, I am now struggling to get other items in without completely bloating the BaseViewData class.
Please can someone help me understand the theory that all the simple examples don't cover.
I use the ViewData extension methods from MvcContrib that add support for multiple strongly typed models (as long as they are different types). Code to add them to the ViewData looks like this:
User currentUser = GetCurrentUser();
List<Project> projectList = projectRepository.GetRecentProjects(currentUser);
ViewData.Add(user);
ViewData.Add(projectList);
Code in the view to pull them out looks like this:
User user = ViewData.Get<User>();
List<Project> projectList = ViewData.Get<List<Project>>();
This removes both the "magic strings" and the type casting. Note, this doesn't do anything with Model property of the view.
Create ONE container class for ever object in your system, and use for all views - simple
Objects with null value have no real overhead
I've ran into the same problem. I think the general solution for most people is to create a container class that contains the Books and Authors models that you really want, and pass that container to your View.
Sub-optimal, yes, but it works. Hopefully this will be addressed in future versions of the framework.