I have three models and their corresponding tables and controllers:
Request
DirectPatch
UTPFiberPatch
The user creates a new request and defines the type of request: Direct or UTP/Fiber
Once the user hits save, the Request will be saved and the user will be redirected to an edit screen to create all the patch entries corresponding to that request.
Each patch entry will be saved as a single row in either the Direct or UTP table depending on the type of request selected. A column called request_id will act as the foreign key.
The view and form will be different for both Direct and UTP/Fiber.
The user can view all requests on a single homepage and click to edit. The user can then see all the patch rows for that request on a single page and click to edit existing or add new.
What would be the best way to set up the routing, controllers and
views for this?
How does the Request ID get passed when creating new patches and automatically saved?
I'm not sure exactly what the technical name is for the problem I'm having if there is one, but I'm happy to add more detail and answer questions if needed.
You could use a polymorphic association on the request model:
belongs_to :patch, :polymorphic => true
Add to your Request table two columns:
patch_id : integer
patch_type : string
When you create a request and the user selects the patch type, you assign this patch object to your request, which will populate the two new columns. From you request model you can then call
request.patch
Which will give you back the appropriate type of patch based on the details stored in the database (note - you can't do eager loading with polymorphic associations).
To do the views you can render a partial in the edit screen, based upon which type of patch it is.
Related
Sorry for rookie question but I want to pass params to controller not related with that view.
I got view with Teams and controller where user adds own favourites teams by marking in Team index.
For example pass additional params to link helper like
link_to 'fav', addfavoriteteam_user_path(team_id:team.id)
and they will be passed to addfavoriteteam action of users controller (provided you have routes set for it)
More RESTful way is to have favorite action for teams.
Or if you want to have a form with checkboxes, you can have it around teams#index, just set form action url to point to another controller
You probably also want accepts_nested_attributes_for for your many-to-many relation model in this case
So lets say I am in /post/2. Which shows me the post with the ID of 2.
Now in controller, how can I see what the current post id is that is being viewed?
My case is a bit different because I am also rendering a partial from another controller into the posts page. And if I delete one of the entries from that partial, I will also need to know the current post id that is being watched.
I'm not sure I completely understand your question, but you can access the ID of any model by simply calling the id method on it. For example if you have a model called Post and an instance of it called #post you would get the id by calling #post.id.
You can get the ID of a model by simply calling id on it. Example: #post.id
If you didn't fetch the model from the database yet, you can get the ID parameter from the URL by accessing params[:id]
I have created a instance variable in rails project, which gets its value from a url parameter like example.com/value. This variable is created in new action, now can it also be used in create action, of the same model.
The value is a id of another model altogether and both the models are associated, I need to create the instance variable in former model.
I need to know, for how long the instance variable is available, and can be use the instance variable of one model in another model.
Clarification with real example
Supposingly there are two models, one is User model and other is Referral model. The root is root :to => 'users#new. Now the user will coming here via example.com/value, where value is the id for Referral model. Now using this value I have to increment two fields: One is visits, which shows how many visits did that particular url bring. Other is signup, which will increment if there is a signup using that value.
I have passed this value via routes in users#new, which I use to increment the visits column of Referral model. Now if the users signup, the users#create would be executed, and I want to be able to use the value in the create action as well, to increment the signup column in Referral model.
As of now, I understand that the instance variable I created in new action to store the value cannot be used in create action. Now how can I achieve this.
In general instance variables only last as long as the user's HTTP request, so they can not be created in one action and used in another.
You could try storing the variable in the session, a hidden input field on the HTML form generated by the new action, or in the urls of links generated by the new action.
I don't know exactly what you are doing, but from the names of your two actions it sounds like there is probably an HTML form involved, so I think the best thing is to use a hidden input, something like this:
<input type="hidden" name="model_id" value="<%= #model_id %>" />
Instance variables only last for that call and in the class they are defined, with the exception of the views. If you have a controller with two methods where one method is your route and another is used internally, then it will be available to both, it is also available to your views.
e.g.
test_controller.rb
def index
something_else
p #variable #outputs "foo" in the terminal
end
def something_else
#variable = "foo"
end
However it would not be available between create and new as these would be called in different requests.
I have a FormViewModel that handles different fields. Many of them have not to be presented to the user (such as modified_date, current_user_id) so I am using hidden fields to respect the FormViewModel structure. When submitted they are passed to the controller's action and correctly saved to the DB but I'm asking: is it the best way to do in ASPNET MVC? I would have preferred to define them in FormViewModel and using only the fields to be modified instead of showing also the non-modifiable as hidden fields.
Is there a better way to do it?
If these fields are not being touched by the user than I would do this;
Create a FormViewModel with only the fields that are relevant. Also the primary key.
The primary key still needs to be on the page me thinks.
Then in the controller you accept the FormViewModel as the argument, you then load the actual model and update, validate fields as required and save the model.
The above is simplistic and you'll have more layers but you should get the idea
I think you can do a few things to make your life a little easier:
Let the URL (and the routing mechanism) give you the id (the primary key of whatever you are trying to edit)
You can have a URL like '/Student/Edit/1' Routing will ensure that your Action method gets the id value directly.
Have 2 action methods to handle your request. One decorated with [HttpGet] to render the initial form to the user (where you just retrieve your object from the repository and pass it on to your View) and a [HttpPost] one to actually handle the post back from the user.
The second method could look something like:
[HttpPost]
[ActionName("Edit")]
public ActionResult EditPost(int id) {
...your code here...
}
Retrieve the actual record from the repository/store based on the id passed in.
Use the UpdateModel function to apply the changes to the database record and pass on the record back to your repository layer to store it back in the database.
However, in a real world application, you will probably want separation of concerns and decoupling between your repository and your view layer (ASP.NET MVC.)
If they are part of the model, the method you are using is perfectly fine. You even have a helper method in HtmlHelper.HiddenFor to output the hidden field for you. However, if the values are something like modified date or current user, you'd might be better suited passing those along from your controller to a DTO for your data layer. I'm making some assumptions about what you're doing for data access, though.
The risk with storing data which shouldn't be modified in hidden fields is that it can be modified using a browsers built in/extension developer tools. Upon post these changes will be saved to your database (if that's how you're handling the action).
To protect hidden fields you can use the MVC Security Extensions project https://mvcsecurity.codeplex.com.
Say the field you want to protect is Id...
On you controller post method add:
[ValidateAntiModelInjection("Id")]
Within your view add:
#Html.AntiModelInjectionFor(m => m.Id)
#Html.HiddenFor(m => m.Id)
On post your Id field will be validated.
Create a FormViewModel with only the fields that are relevant. Also the primary key.
The primary key still needs to be on the page me thinks.
Then in the controller you accept the FormViewModel as the argument, you then load the actual model and update, validate fields as required and save the model.
The above is simplistic and you'll have more layers but you should get the idea
Many of the available controller methods (chain, forward, redirect) take a map which can include keys such as:
id
params
model
A couple of questions about these:
Is 'id' just an alias for a request parameter named 'id'? In other words, is there any difference between:
chain(controller: "member", action: "showProfile", params: [id: memberId])
and
chain(controller: "member", action: "showProfile", id: memberId)
The chain method (possibly among others) allows passing a model and/or params (map) from controller action A to B. Practically speaking, what's the difference between passing data from action A to B via the params and model maps? Also, if the data is passed in the model map, how do I access it in controller action B?
Everything Burt said is correct. In addition, the reason that you'd want do do a chain (if you have a model) or a redirect (if you don't have a model to keep) is because both of those methods return a 302 redirect response to the browser. The browser then knows to ask for the next page.
It then has the correct url in the header for the resulting page, rather than the url from the page where the original request was from.
This pattern is very useful after a POST of information as it avoids all kinds of trouble with bookmarking, and resubmitting of information if the user hits refresh on the resulting page.
Ex: if you're saving a Book and you want to render the list page if the book is successfully saved. If you just call "controller.list()" in your method, it will show the user the list of books that gets rendered, but the url bar will still say ".../book/save". This is not good for bookmarking or reloading. Instead, calling redirect/chain will send the 302 response to the browser telling it to ask for the ".../book/list" page, which it does. All of your variables (your model and other flash messages) are in flash scope so they're still available to your model/view to use and everything is happy in the world.
This pattern is called Post/Redirect/Get.
'id' comes from UrlMappings entries such as "/$controller/$action?/$id?" - see http://docs.grails.org/latest/guide/single.html#urlmappings for usage.
Params are querystring parameters or form post parameters, accessed in non-Grails apps using "request.getParameter('foo')" but simplified in Grails as "params.foo". The contents of the model map are stored in the Request as attributes, accessed in non-Grails apps using "request.getAttribute('foo')" but simplified in Grails as "request.foo" or more typically accessed directly in GSPs, e.g. "${foo}".