I'm pretty new with Ruby on Rails. I have done tutorials and an online class. I know enough to have my way around the development environment, to create tables, controllers, views etc. However, the classes and tutorials don't really show you in depth things you may have to work with in a real software development situation.
I'm in the process of converting a piece of software to the Ruby on Rails platform. Here is the situation. I have a Salesman controller that has salesman information. Then i have a client controller that handles client information. A salesman has many clients and clients have one salesman. I already coded the REST architecture for the Salesman object. Now, i have to create the client. But before i can get to the new action in the controller, i have to select a salesman first. This select salesman page is going to be needed on many other occasions as i will have other controllers such as commissions , purchase orders etc that have to be tied to a salesman first. How do i proceed to code such a "temporary select" page before actually going to the new action in the controller. Can we define custom actions after which i would just redirect_to the new action passing the salesman id as a param?
You need to design the app similar to a multi-tenant app. In your case, Sales Person is like a tenant.
Here is the conceptual design:
add current_id class attribute to SalesMan
cattr_accessor :current_id, instance_writer: false, instance_reader: false
In all your models that belong to a sales person, define the default scope:
default_scope { where(sales_man_id: SalesMan.current_id) }
Ensure that current sales man is set before executing any actions that depend on sales man being pre-selected. There are multiple approaches for achieving this and it also depends what kind of user experience you want to provide. Couple of options:
Only show the navs such as New Client only if a salesman is pre-selected. Provide a menu option to select a salesman. In that action set SalesMan.current_id.
If the salesman is going to be different across many subsequent transactions, you may want to implement a salesman selection (step 1 of workflow) through a controller before action. For example, when user selects New Client nav option, the before action can redirect to sales man selection and set a flag. SalesMan controllers selected action should redirect to New Client action and ensure that proper flags (parameters) are set to avoid cycles. Define a new controller SalesManSelectionController and subclass all the controllers whose models depend on salesman.
Related
I'm building my first MVC project and I have a question about the model.
Each webpage can only contain 1 model, yet my page will require 2 models, one is the search option (the ability to narrow your search such as selecting price range, colour etc) as well as the data.
Is it really as simple as creating a new Model, similar to a ViewModel which in this case would only have 2 properties, a SearchModel and a ProductModel?
Yes, there are really two "models" which is sometimes confusing. There's the "View Model" and the "Domain Model." The view model is passed directly to and from the view. The domain model describes the real-life domain that you're dealing with and is what the database persists. Often, they are the same thing, such as if you're displaying information for a single real domain object (e.g., a car). If you have two domain models that go on one page, you should make a view model with both as properties.
If you are looking to have two models in a view then this question might provide useful information:
multiple-models-in-a-view
Edit:
A good example is the 'Manage' view in the default 'Account' controller of a fresh mvc app. It uses a partial view to handle the changing of a user's password. Whilst both views are using the same model type it shows how to implement a partial view. In this case both the main view and the partial are submitting to the same method on the controller, hence they need to use the same model (which is a parameter for the controller method). But if the partial were to invoke a different controller method then the submitted model could be different. Hope this makes sense :)
Trying to figure out the best way to organize a ASP.NET MVC site. Take a very simple 1..N relationship: Company can have many Contacts, Contacts must have exactly one Company.
I have your typical routes:
Company/Index (list all companies)
Company/Details/{int} (details of Company {int})
Company/Create (create new company)
Contact/Index (list all contacts)
Contact/Create (create new contact, company is selected from drop down)
Now if I wanted to create a page that created a Contact in the context of a Company (from the Company detail page) so that the required company is filled in/not editable), what would be the best route of going about that, while not duplicating code where possible.
Not sure if I can leverage the Contact/Create logic/view from the Company controller (and be able to route back to the Company Details page when complete), or mess with the routes to do something like Company/Details/{int}/Contact/Create (not even sure if that makes sense or would work)?
There has got to be a better way then me adding my logic and view for adding a Contact into my Controller view and having it duplicated.
Cant find the link, but found some information about using named routes to help out :)
In my model I have relationships like this:
[Person]
PersonId (PK)
...
[Orders]
OrderId (PK)
PersonId (FK to Person.PersonId)
...
A person can have multiple orders.
I generated PersonController with Create/Details/List/Edit views. I want to be able to manipulate Orders also, but within the context of a Person. In other words, I'd like the workflow to be
User browses a list of people (/Persons)
User selects 'View Orders' link next to a specific Person (/Persons/4/Orders/)
User sees a list of orders with Create/Details/Edit as well (/Persons/4/Orders/Edit/38)
Is this the right way to set up my controllers/routes?
Should I just access orders at routes like (/Orders/Edit/38) instead?
Right now I have:
PersonController
OrderController
Should I create a PersonOrderController or can I achieve what I want using only the two controllers I already have?
You should probably use just the two Controllers you already have. It is a judgment call however. Two different excellent MVC designers might do this two different ways. Unless you already see a lot of other work for your OrderController, you should start with two controllers. If OrderController becomes bloated, you can refactor.
Im building an admin interface for a medical records management app.
My client has asked me for a way to easily select the patient the user wants to work with without having to select the patient everytime he wants to perform an action.
So, say for instance he wants to store a record for the patient's current status (weight, size, etc) and then assign the same patient to a different doctor or change the company the patient currently works for.. he doesnt want to select the same patient all three times... he wants a select dropdown for patients and perform the different actions for that patient.
Im thinking this should be somehow stored in a session variable.. I have a table of patients and Im using LinqtoSql classes.... what do you reccommend?? help please.
Sounds like you want to put something into Session--perhaps some of the basic "recent patient" information, such as a patient ID, patient name, etc.
Definitely take a look at this post on how to do it in a very graceful way.
You could use the session to keep a list of recently active patient records for a given users session. Every time the user selects a new patient simply add that patient's name to the "Recent" list. Since you can control the length of the session you could just allow the list to expire when the user's session does. As far as not making the user select a customer again, just have it auto-select the most recent (last entry) on the list of recent customers.
Personally I would consider caching as an option here. By the sounds of it you want to load ALL data for ALL patients which is fine for a small amount of data but will not scale gracefully.
Consider going to the database the FIRST time you need the patient's data, and getting your data from the cache for subsequent queries...
The best way is to have the id in the route.
Use something like this when registering routes:
routes.MapRoute(
"Standard",
"{controller}/{action}/{PatientId}",
new
{
controller = "home",
action = "index",
PatientId = ""
}
);
When you select a Patient you post to an action that sets the PatientID in the RouteParameterCollection and redirect to the the action that displays the form for changing the patient. this way you always have the patientID in the URL.
Using session has some drawbacks:
If you have 2 windows open both use
the same session. This might confuse
users.
You can not bookmark a page
Session is usually stored in memory
on the appserver. This might lead to
performance problems if extensively used.
My domain model is this: we have a bunch of schools as the root of the "hierarchy". Each school has teachers and courses, and each course has one teacher. I am trying to model this with the logic of the mvc framework and I 'm quite confused. For example, the \school\details\x should give the first page of a school. That should contain a link to a list of its teachers, and a list to each courses.
A list of teachers means that the index action should be parametric to the school the user is looking at: \teacher\id where id is the school. The same with the course list. And then create teacher or course should also be parametric to what school we are looking at:\teacher\create\x where x=school.
How do I carry around the school id? Is there some neat way to do it, or do I need to pass it around all the time, into every view that needs it? It also makes the site URLs very cryptic. I was thinking of a way to make the url structure like {school-alias}\{controller}\{action}\{id}, still I have to find a way to pass around the school. If this is accomplished, then I need to implement some kind of filter that will not allow a user to perform certain actions if the schoolId he is requesting does not match the one in his profile.
I figure that if I 'm carrying the schoolid around the URL, the site is more REST-like, compared to, for example, getting the schoolId from the user's profile.
I would create acronym for every school. For example:
School no. 1 - ABC
School no. 2 - DEF
If i wanted to list teachers, I would write
http://site-address/ABC/teachers/list or just http://site-address/ABC/teachers
To show basic information about school
http://site-address/ABC
The code for routing would be:
routes.MapRoute(
"Default", // Route name
"{acronym}/{controller}/{action}/{id}", // URL with parameters
new {controller = "School", action = "Details", id = ""} // Parameter defaults
);
I would create authorization action filter on teachers,school and classes controller to check if user has access to school defined by acronym parameter in URL. You can check it by comparing filterContext.RouteData.Values["acronym"] with data stored in profile.
Write an extension method to overload rendering of links that extracts the school identifier ( acronym or whatever you choose to use ) from the routing data and adds it to the route values already passed in. This way your action can choose to use the identifier if it is present but is not required to add it to the view data and you do not have to remember to include it in any action links ( you just have to remember to use your action link overload ).
I would make the action link overload quite obviously different so anyone following behind you can see you are doing something unusual. This could be as simple as Html.SchoolActionLink( ...).
For example:
If your url is http://mydomain.com/abc/teachers/list and your route is defined as {school}/{controller}/{action} then the route value dictionary will have the value "abc" at the key "school". The route values can be accessed via HtmlHelper.ViewContext.RouteData.Values.
In the end I 'm answering my own question.
The real solution to this is :Restfull Routing. It implements the functionality in RoR, which is exactly what I need. Too bad this is not a requirement from more people so that it can go into mvc-trunk.