I'm trying to pass Param data from view to controller and I'm having trouble. Here's what I'm currently trying to do.
View:
<form action="${doStuffURL}" method='post' params="[keyId: ${mykey.id[i]}]"><g:actionSubmit value="doStuff"/></form>
Controller:
def myObjectService //inject service object
def doStuff = {
myObjectService.doStuff("${params.keyId}") //this blows up because it's value of NULL
myObjectService.doStuff(8) //this works fine
}
It gets to the method block because the error log says "no signature of method MyObject.doStuff() is applicable for argument types: values: [null]." Also, I'm able to see ${mykey.id[i]} data from another field, so the data is definitely in the view.
How can I get the controller to read the Param data?
Thanks!
err lots wrong here:
<form action="${doStuffURL}" method='post' params="[keyId: ${mykey.id[i]}]"><g:actionSubmit value="doStuff"/></form>
why not use:
<g:form name="something" controller="yourController" action="youraction">
As you can see above you are having to generate
form url (maybe you have your reasons)
Controller:
def doStuff = {
MyObject.doStuff("${params.keyId}")
}
Differences between action and methods in Grails controllers
So firstly why you should change controller but my actual concern here is
MyObject.doStuff
is MyObject.doStuff a static method ?
since that is only when a call like this would work. The link shows a static method. gets called here and it may confuse you due to it calling it via executor.registerSenderFault due to how it is generated working - expandability - for future classes that do same thing. this could have been EmailExecutor.registerSenderFault which is the full class in uppercase like you have declared.
surely it should be a service notice starting with lower case.
myObjectServive.doStuff(stuff)
If above is some real method in MyObject and is not a static method then you need to instantiate the class
MyObject myObject = new MyObject()
myObject.doStuff(stuff)
but in short this is why services exist it is all there to save you all the hassle since they just get injected.
I suggest you do some reading looking around
E2A
def doStuff = {
println "my params are $params "
//do you see keyId in there ?
//if so what is doStuff expecting as input a string ?:
// since if you do
println "${params.keyId.getClass()}"
//by default it will be a string you may need to change it from:
//myObjectService.doStuff("${params.keyId}")
myObjectService.doStuff(params.keyId as Long)
}
Personally I don't think it is any of the above edited comments, it still relates to how/what you are injecting. I have seen similar issues. I would suggest you create a brand new service and inject new service as a test and start again - not convinced you were injecting it correctly or if you are the service may be some abstract class rather than a normal service. Or.... you are making some form of similar mistake in the uppercase/lowercase declaration of the service name so you may have created:
MyObjectnameService and calling it using myObjectNameService difference in N in those or.... even worse you have created actual service as myObjectNameService with lowercase name.
test this all again using a much simpler naming convention and create a new service as a test
grails create service MyService
and try again using this service
Related
When I use generate-all package.DomainObject, it generates a controller where create action is generated as:
def create() {
respond new DomainObject(params)
}
When I call the localhost:8080/DomainObject/create even without making any code change, it throws an exception:
groovy.lang.MissingPropertyException: No such property: controller for
class: package.DomainObject
It looks like introspection is failing for properties that params map has and DomainObject does not have. This is surprising because in the grails 2, introspection used to just ignore the non-matching properties and it also used to do necessary type conversions on fields as well (now if DomainObject has an int property, it will throw a type mismatch exception because params map passes it as String). This is really inconvenient. Did something change or I am missing something?
Using the map constructor and setting properties in bulk with a map in Grails is basically the same as in Groovy, but it has logic to exclude 'controller', 'action', and 'format' keys to keep controller code like this uncluttered. That broke in 3.x and has been reported in the issue tracker. It's not marked fixed but works correctly for me in a simple 3.0.4 test app.
As a temporary workaround you can copy the params map and remove values stored under those keys and use the 'fixed' map for the constructor:
def create() {
def fixedParams = ([:] + params) // copy
['controller', 'format', 'action'].each { fixedParams.remove it }
respond new Thing(fixedParams)
}
I have problems in organizing my code when I want to update a non-simple domain object. The problem is to separate responsibilities for the controller and the service layer.
More explicitly, assume that we have a domain class Client that depends on other domain classes like Address and so on.
In the view there is a gsp for editing some of the Clients properties including some of the nested properties like street on the Address.
When I would like to update those fields I call the update method on a Controller (in this case the ClientController).
I like the feature coming from the errors of a domain class when validated. Like if I in the Controller write
Client client = Client.get(params.id)
client.properties = params
client.validate()
If the client now has errors it is very easy to display them in the edit view.
But, I thought that updating, saving and getting the client from the database (Client.get(theId)) should be handled by the service layer. In my case I have to update or create other domain objects (like the Address) before I update the Client.
So one of my questions are how should the API look like for the service layer?
public ... updateClient(…)
In the literature they have the trivial example of updating the age of a person. So, their API consists of the id of the person and the new age. But, in my case I have about ten params from the view and they are just a subset of all properties of a client and I don't know which one of these that have changed.
I would like to have a Client in the controller that I can validate and resend to the edit view if it has validation errors.
I would like to handle the database interactions and transactions from the service layer.
How can I combine these? What responsibilities should the different layers have regarding update? How should the API of the service layer look like regarding update?
If there is a good reference implementation somewhere I would be happy to study it. Many times the service layer is unfortunately totally or partially ignored.
The missing piece of this puzzle is command objects. These classes represent the contract for your API into your services and provide you the ability to have a concrete class for your views and for validation. Let's look at an example.
Given a domain class of Client which as an Address and several Phone instances your Service layer might look like this:
...
class ClientService {
def updateClient(ClientUpdateCommand cmd) {
..
}
}
...
While the ClientUpdateCommand looks something like this:
#grails.validation.Validateable
class ClientUpdateCommand {
Long id
String name
List<PhoneUpdateCommand> phoneNumbers = []
AddressUpdateCommand address = new AddressUpdateCommand()
...
static constraints {
id(nullable: false)
name(nullable: false, blank: false, size:1..50)
...
}
...
}
You will note that this command object is composed of other command objects, and has constraints for validation. It may seem like you are replicating your domain classes here, but I have found that the more complex your application then more differences will appear between the domain classes and your command objects.
Next up is the use of the command object within your controller and your views. A controller method may look something like this:
Class ClientController {
...
def clientService
...
def edit(ClientUpdateCommand cmd) {
...
cmd = clientService.load(cmd.id)
Map model = [client: cmd]
render(view: 'edit', model: model)
}
def update(ClientUpdateCommand cmd) {
Map model = [client: cmd]
if (cmd.hasErrors() {
render(view: 'edit', model: model]
return
} else {
clientService.update(cmd)
...
}
...
}
}
I have left a lot out of the controller as I didn't want to bore you with the details but rather show how a command object replaces the domain instance. In some ways it's a little bit more work but it moves you completely away from manipulating the domain classes and delegates that to the service you have created. You will also notice that the command object replaces the domain class instance for your model for your views. I won't bother giving you any examples of the GSPs since they really don't change much when using command objects like this.
I'm sure there could be entire chapters of books written on the subject, but hopefully this gives you some insight and you can see that the answer to your question(s) is: Command objects.
I'm making a web app that stores reports of various types as domain objects, so I have a domain object HeadOfHousehold which contains name data, and references to other domain objects such as the reports, addresses, and any dependants. I am trying to build a list of recently viewed/created HeadOfHousehold objects. After multiple Google searches, and scouring the manual, it appeared that a service would be an appropriate solution. So I created ClientListService:
#Transactional
class ClientListService {
static scope = "session"
String message // right now I'll be happy to just see the same message across
// pages I can add a list and manipulate it later.
}
I thought I could then reference it in my various controllers, and it would persist Something like this:
def clientListService
def index(){
hasSearched = false
clientListService = new ClientListService(message: "Hello")
[errorMessage: params.errorMessage, clients:clientListService]
}
Which should be available in a later controller:
class HeadOfHouseHoldController {
def clientListService
def index() {
[customer: HeadOfHousehold.get(params.id), clients: clientListService]
}//...
However when I try to get the message, it appears as if the object is null.
From my index.gsp:
***************${clients?.message}********************
So I don't know if I am not defining session properly (I'm not doing anything special to do so), if I'm misunderstanding how the session scope works, or something else. I do see the proper message on the original page which has defined the object, however I don't see it on any subsequent pages.
Also, I'm not sure if this is the proper way to go about this; right now all I really need is the list of HeadOfHouseholds that I would need (so I can add to the list from other pages), however I can see possibly adding other logic and items into such a class.
I think you understood the session scope correctly. Each Spring bean with a session scope is bound to the HTTP session.
But your first controller listing does it all wrong. You are not supposed to instantiate the service class yourself. This is what Spring (Grails) does.
class FooController {
def clientListService // gets autowired by Grails/Spring
def index(){
hasSearched = false
clientListService.message = 'Hello' // only assign a String value to the service
[errorMessage: params.errorMessage, clients:clientListService]
}
}
This means you cannot not do something like
clientListService = new ClientListService(message: "Hello")
and expect your code to work. Hope this helps.
I'm trying to use the built-in laravel's Ioc container to inject a PageManager class inside a Page model and I'm a little lost.
What I'm trying to achieve is something like that:
class Pages extends Eloquent {
public function __construct(PagesManagerInterface $manager, array $attributes = array())
{
parent::__construct($attributes);
$this->manager = new $manager;
}
public function saveToDisk()
{
$this->manager->writeToFile();
}
But I obtain this error:
ErrorException: Argument 1 passed to Pages::__construct() must be an instance of PagesManagerInterface, none given.
I tried to add this in app/start/global.php:
App::bind('Pages',function(){
return new Pages(new PagesManager);
});
But is seems ignored by the framework, and also i don't know how to insert the $attribute array into this declaration.
I'm a little lost so any help is appreciated!
It's not a good idea to overload a model's constructor because new instances can be spawned behind the scenes through various methods, like Model::find().
When that happens, the dependencies you're asking for in your custom constructor aren't being passed in because the Model class isn't aware of them. So, you get that error message.
See the find() method here: http://laravel.com/api/source-class-Illuminate.Database.Eloquent.Model.html#380-397
See this post by Jason Lewis: http://forums.laravel.io/viewtopic.php?pid=47124#p47124
I think that what you need is:
App::bind('PagesManagerInterface',function(){
return new Pages(new PagesManager);
});
This tells Laravel to inject a new Page object everytime it needs an instance of your PagesManagerInterface wich wasn't passed while creating the model.
In Laravel you can use the IoC Container:
public function saveToDisk(){
$managerObject = app()->make('path\to\class\PagesManagerInterface');
$managerObject->writeToFile();
}
I have been looking for quite some time now on this problem.
Here's the deal.
I'm building a website that calls to a Web API to get its data. My Web API uses a library, working with repository pattern. My database model (EF Model-first) was build in the library. In that model I have a base class Pass. Then I have two derived classes, CustomerCard : Pass and Voucher : Pass. My model from EF Designer
I have a method to get all the CustomerCards.
public IQueryable<CustomerCard> GetAllPasses() {
IList<CustomerCard> allCards = new List<CustomerCard>();
var c_cards = context.Passes;
foreach (var c_card in c_cards) {
if (c_card is CustomerCard) {
allCards.Add((CustomerCard)c_card);
}
}
return allCards.AsQueryable<CustomerCard>();
}
In my ApiController, I use this method to get the passes and return them to the website, like this:
[HttpGet]
[Queryable]
public IQueryable<CustomerCard> GetAllPasses(string version) {
return passRepo.GetAllPasses().AsQueryable();
}
My Web API returns JSON format. This is my config to preserve referencing and stuff:
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.Objects;
json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
config.Formatters.Remove(config.Formatters.XmlFormatter);
I'm using IQueryable because I want to be able to page the data on my website. The api method is available at '/api/v1/passes/all'.
Here's the strange part. To test my paging, I call 1 pass per page.
For my first Pass, it works fine. But when I go to my second page, he also gets the correct pass, but the reference to User is gone.
As you can see in my model, the CustomerCard class has a property User. This indicates who owns the customer card.
So this call loads the user from the pass: 'api/v1/passes/all?$top=1'
but when I call to this one, the user instance is NULL: 'api/v1/passes/all?$top=1&$skip=1'.
However, when I call to 'api/v1/passes/all?$top=2', the User for the second pass IS loaded.
So this is where my mind get's blown! I don't get it? Why doesn't the user-reference comes along with the second one? Could it have something to do with the Lazy loading feature of the EF?
EDIT
When I use the extension method Include on context.passes, an error is thrown:
A specified Include path is not valid. The EntityType 'LCS_Model.Pass'
does not declare a navigation property with the name 'User'.
This is because Passes as a dbset, contains CustomerCard as well as Voucher. Is there a way I can tell my context to expect or convert it to a CustomerCard?
Can someone please help me. If you don't understand my question, ask away!
Thanks allready!
EDIT 2
The method on my API controller is now
[HttpGet]
[Queryable]
public IQueryable<CustomerCard> GetAllPasses(string version) {
return context.Passes.Include("User").OfType<CustomerCard>();
}
This gives me my correct items. I have 2 customer cards in my db. Both are from the same user. My API has the user still loaded. The moment my website receives the response, the User property becomes null. My guess is that it's because it is still referencing to the same user from the first element of the array. Is that possible? And if yes, how can I prevent that from happening?
Yes, you need to make sure any related records are included when you do your query. See this for some examples. Secondly... I fail to understand why you are doing all that work with the for loop... That's a lot of absolutely needless and wasted work for the server to do if you want to do any paging. I'm thinking, besides any other filters you might want to apply, your GetAllPasses should look something like this.
public IQueryable<CustomerCard> GetAllPasses() {
return context.Passes.Include(r => r.User);
}
Edit (2): I need to read better. I have to confess, I'm not familiar with type inheritance in EF. I found some things that might work here: table per hierarchy, table per concrete type, and see also also MSDN Queryable.OfType<TResult>. This is a guess, but let's try:
public IQueryable<CustomerCard> GetAllPasses() {
return context.Passes.OfType<CustomerCard>().Include(r => r.User);
}