I have two controllers: controller A and controller B and I'm calling a controller A's actions from Controller B like this:
AController.dispatch(:get, request, response)
my question is - is it a better practice to pass on a copy of the request response objects?
What is the correct way of using ActionController::dispatch method
Clarification
I have to call controller B from controller A its a constraint... now the question was specifically regarding 'dispatch'...
You shouldn't be using it at all in application code.
ActionController.dispatch is the internal implementation of how Rails calls your controller as middleware and how the depreachiated controller tests were implemented. Rails doesn't actually clearly destinguish between the components that are a part of the makeup framework and its "public APIs" that are intended for use in your application but this definitely the former.
The main reasons you should not be using it in this situation is that it breaks the entire idea of what controller should be doing - responding to HTTP requests when they are hit by the router.
It creates a strong coupling between different controllers (that should not be coupled) and can have very unexpected side effects.
If what you're looking to do is reuse code there are also much better options:
Inheritance
Mixins (aka Concerns)
Service objects
Related
In my current project, i notice few thing,
Maximum part of the business logic are moved to helper.
Included all helper files in a module under lib directory and included that module in application controller.
In many methods, no argument passed, instead they used the instance variable(create instance variable in calling method and use that instance variable in the called method).
Each action will call a helper method to execute business logic and that method will call some other helper methods.
All method are written as public, No protected and private method.
Models are used only for validation.
are those points follows good coding conventions? if not, can you suggest me the best coding standard to improve performance?
First, convention has nothing to do per se with performance.
Maximum part of the business logic are moved to helper.
I would say this is very bad. One of the popular idioms is "fat models, skinny controllers", which works most of the time. Put all the business logic you can in your models, where they belong. If you have really complicated views you want to simplify, use decorators (e.g the draper gem), and then separate business logic (model) and view logic (decorators) into their according locations.
Included all helper files in a module under lib directory and included that module in application controller.
Okay I think. As long as you have one place to maintain that chain, it feels okay. If it leads to misunderstandings/misusings/hacking around, then: not okay.
In many methods, no argument passed, instead they used the instance variable
If you're talking about methods in your model: this is good, since the method is targeted at the scope of your instance, and not of your class.
Each action will call a helper method to execute business logic and that method will call some other helper methods.
Sounds strange. The controller is responsible for preparing your data used in the view. If you are preparing specific data in your helpers to assign them to your view for usage, consider putting these into a decorator (as mentioned above). But calling a helper in almost every action sounds like something is done the wrong way.
All method are written as public, No protected and private method.
Non-public methods should not be public. Take a look at helper_method and hide_action from ActionController.
Models are used only for validation.
Wrong. Models contain the business logic, as mentioned above. What about modifying things in the console? Would you want to update all logical related data by hand, then? Do you do this "by hand" in your controller right now (which it seems like) ? What about when you introduce an API, do you copy-paste the code in there to not miss some logic? And what when the logic changes, are you really sure all required endpoints manually and independently handling that logic are also updated?
There's a reason models have relations, callbacks and instance methods. Use them!
Performance is not related to your arguments; they are about project organization.
Maximum part of the business logic are moved to helper
This shouldn't happen, you should move the business (aka models) logic inside the models. Rails doesn't force you doing it, so keeping the logic organization is up to developers.
Models are used only for validation
This is a consequence of putting the business (aka models) logic outside the models. You should move it from the controllers/helpers to the models. Again, Rails doesn't force you to do that, so it's up to developers to do it.
Included all helper files in a module under lib directory and included that module in application controller.
In many methods, no argument passed, instead they used the instance variable(create instance variable in calling method and use that instance variable in the called method).
Each action will call a helper method to execute business logic and that method will call some other helper methods.
All method are written as public, No protected and private method.
I think that these points are (some more, some less) related to the Rails Helper design. One flaw of Rails is the Helper design: they go against the OO pattern and usually end up by being a bunch of unorganized functions, à la PHP.
For this reason some people use Decorators. Decorators "add an OO layer of presentation logic" (from Draper), allowing to organize better the view related methods.
If you want to examine the argument, I suggest you the following links:
Google search about decorators
Draper
The Ruby Toolbox, presenters category
I have almost all of the "shared" statements in functions in my model. The problem is that I am getting the following error, when I need to use more then one of these functions in my controller:
Controller action should call one model method other than an initial
find or new
and the IDE goes deeper explaining that:
This inspection warns if a controller action contains more than one
model method call, after the initial .find or .new. It’s recommended
that you implement all business logic inside the model class, and use
a single method to access it.
Is this mean that all of the logic should be put in more complex model functions? I have thought that the work of the controller is to call model functions and passes the results to the view.
If I put back the model functions code back to the controller, everything will work, but I will get a code duplication in all my controller actions.
So, what is the right approach here?
The warning message indeed means that the logic should be put in a single model function, but not necessarily more complex ones. To avoid model duplication and/or the "fat model" problem, you may need to introduce additional classes that the model relies on.
Yes, the work of the control is to call model functions, but only as a thin veneer, per this inspection guideline of one model function per controller action aside from an initial create/find.
I'm not sure I understand your comment about getting code duplication in your controller if you move functions back up, since you can always introduce shared functions at the controller level. But again, that's not the recommended approach of "thin controller" and "reasonably thin model" with supporting classes as required.
What additional advantage does IControllerActivator.Create (new in MVC4) provides when controller can already be custom created (and resolved using DI) by overriding CreateController method of DefaultControllerFactory?
The controller activation logic was pulled out of the default controller factory, and put in the controller activator; so it was done to make it a little more flexible and follow the singular responsibility pattern. Depending on what version of MVC you use, it now uses the controller activator to create the controller. The two work hand-in-hand to get the job done; therefore, you can customize either, and it will function similarly. I don't see there being an advantage one over the other.
See Brad Wilson's blog post about this.
My base controller has:
[Authorize(Roles = "sys_admin")]
I want to have one action in a controller that's different and is available to "user" and "sys_admin". Can I override and how do I do that?
Also any suggestions on what else I could put in a base controller that might make my coding simpler. For example what's in your base controllers?
Anything that you use in every controller - attributes, methods, properties, etc. The same stuff you would put in any base class.
Just to add to the discussion, I have a few extra utility methods in my shared controller. I write a bunch of little apps for corporate use, so I try to repeat code as little as possible here.
getContext(): Puts together an object containing user info like IP, hostname, id, etc. for logging purposes.
Shared Views/Partials such as Error, Default, and Redirect (used for redirecting ajax requests).
RedirectToError(): I created this to use similar to RedirectToAction. I load up an ErrorObject with info, throw it in session, and return a Redirect to my Error page.
General logging and tracing methods so I can quickly spit out information to a file.
I override OnActionExecuting and check if my session is still valid and redirect to login if its not. Probably better with attributes...went with quick and dirty. Also trace Url.PathAndQuery for debugging here.
Any data access actions that I would use across views with ajax, like loading up a list of departments.
OnException is overridden, as well.
That's what I got in mine so far.
In my base controllers I actually put some utility method ([NonAction]) collected over time. I prefer to add functionalities to Controllers by decorating with Attributes if possible.
Lately my base controller has:
some Properties for retrieving information about the current user (my app
specific informations, not the User.Identity stuffs)
A simple protected override void OnException(ExceptionContext
filterContext); override for at least logging unhandled exception and have
some sort of automatic notifications
A bunch of Cookies related methods (WebForms auth cookies management
for example)
A bunch of usefull standard attributes (usually [Authorize], [HandleError], [OutputCache]) in its declaration.
some standard method for preparing widely used json data types on the fly (when possible I prefer to have a standard json object with ErrorCode, ErrorMessage and a UserData).
With time you'll find more and more utilities to keep with your controllers, try to keep an assembly with the simpler ones (avoiding heavy dependencies), will come handy with your next MVC projects. (the same goes for Helpers and to some degree also for EditorTemplates).
For the Authorize Attribute part, well, I think the cleanest way is to write your own AuthorizeAttribute class, specifically a NonAuthorizeAttribute. I think I've also seen it somewhere on SO.
You can also play with the Order Property of the default AuthorizeAttribute - put different Order in BaseController and in Action, in order to have Action's one executed first, but I cannot recall if you can actually break the Attributes processing chain.
Regards,
M.
We cant tell you what you need in your base controller, you have to reveal these kind of thing as you implement your controllers and see repeating code.. Dont hesitate to refactor these things to your BaseController, and keep in mind, that maybe you should have 2 or more BaseControllers, or 2-layer hierarchy of BaseControllers.
I give you two tips, what i always have in my BaseController :
super-useful helper method for interface-based model binding :
protected T Bind<T, U>()
where T : U, new()
where U : class
{
T model = new T();
TryUpdateModel<U>(model);
return model;
}
You can then have multiple "sets" of properties you want to bind in different scenarios implemented as interfaces, and simple model bind your object (even existing object, from DB) with incoming values.
2.If you use custom AcionResults (maybe your specific Json builders etc.), make your "shortcuts" methods in BaseController. Same thing as View() method is shortcut for return new ViewResult(...)
To add more to the good responses already here -
caching caching caching caching
See
Disable browser cache for entire ASP.NET website
I've seen a lot of people talk about using base controllers in their ASP.NET MVC projects. The typical examples I've seen do this for logging or maybe CRUD scaffolding. What are some other good uses of a base controller class?
There are no good uses of a base controller class.
Now hear me out.
Asp.Net MVC, especially MVC 3 has tons of extensibility hooks that provide a more decoupled way to add functionality to all controllers. Since your controllers classes are very important and central to an application its really important to keep them light, agile and loosely coupled to everything else.
Logging infrastructure belongs in a
constructor and should be injected
via a DI framework.
CRUD scaffolding should be handled by
code generation or a custom
ModelMetadata provider.
Global exception handling should be
handled by an custom ActionInvoker.
Global view data and authorization
should be handled by action filters.
Even easier with Global action filters
in MVC3.
Constants can go in another class/file called ApplicationConstants or something.
Base Controllers are usually used by inexperienced MVC devs who don't know all the different extensibility pieces of MVC. Now don't get me wrong, I'm not judging and work with people who use them for all the wrong reasons. Its just experience that provides you with more tools to solve common problems.
I'm almost positive there isn't a single problem you can't solve with another extensibility hook than a base controller class. Don't take on the the tightest form of coupling ( inheritance ) unless there is a significant productivity reason and you don't violate Liskov. I'd much rather take the < 1 second to type out a property 20 times across my controllers like public ILogger Logger { get; set; } than introduce a tight coupling which affects the application in much more significant ways.
Even something like a userId or a multitenant key can go in a ControllerFactory instead of a base controller. The coupling cost of a base controller class is just not worth it.
I like to use base controller for the authorization.
Instead of decorating each action with "Authorize" attribute, I do authorization in the base controller. Authorized actions list is fetched from database for the logged in user.
please read below link for more information about authorization.
Good practice to do common authorization in a custom controller factory?
I use it for accessing the session, application data etc.
I also have an application object which holds things like the app name etc and i access that from the base class
Essentially i use it for things i repeat a lot
Oh, i should mention i don't use it for buisiness logic or database access. Constants are a pretty good bet for a base class too i guess.
I have used base controller in many of my projects and worked fantastic. I mostly used for
Exception logging
Notification (success, error, adding..)
Invoking HTTP404 error handling
From my experience most of the logic you'd want to put in a base controller would ideally go into an action filter. Action Filter's can only be initialized with constants, so in some cases you just can't do that. In some cases you need the action to apply to every action method in the system, in which case it may just make more sense to put your logic in a base as opposed to annotating every action method with a new actionFilter attribute.
I've also found it helpful to put properties referencing services (which are otherwise decoupled from the controller) into the base, making them easy to access and initialized consistently.
What i did was to use a generic controller base class to handle:
I created BaseCRUDController<Key,Model> which required a ICRUDService<TModel> object as constructor parameter so the base class will handle Create / Edit / Delete. and sure in virtual mode to handle in custom situations
The ICRUDService<TModel> has methods like Save / Update / Delete / Find / ResetChache /... and i implement it for each repository I create so i can add more functionality to it.
using this structure i could add some general functionality like PagedList / AutoComplete / ResetCache / IncOrder&DecOrder (if the model is IOrderable)
Error / Notification messages handling: a part in Layout with #TempData["MHError"] code and a Property in base Controller like
public Notification Error
{
set { TempData["MHError"] = value; }
get { return (Notification) TempData.Peek("MHError"); }
}
With this Abstract classes i could easily handle methods i had to write each time or create with Code Generator.
But this approach has it's weakness too.
We use the BaseController for two things:
Attributes that should be applied to all Controllers.
An override of Redirect, which protects against open redirection attacks by checking that the redirect URL is a local URL. That way all Controllers that call Redirect are protected.
I'm using a base controller now for internationalization using the i18N library. It provides a method I can use to localize any strings within the controller.
Filter is not thread safe, the condition of database accessing and dependency injection, database connections might be closed by other thread when using it.
We used base controller:
to override the .User property because we use our own User object that should have our own custom properties.
to add global OnActionExecuted logic and add some global action-filters