createLink in ApplicationTagLib from service - grails

I am trying to learn about creating the link using createLink from ApplicationTagLib called from the service.
Grails : 3.2.8
Code :
def applicationTag = new ApplicationTagLib()
def abc = application.Tag.createLink(controller:"accomodate", action:"menu", id:4)
Error :
org.grails.taglib.GrailsTagException: Tag [createLink] does not exist.
No corresponding tag library found.
I am very new to this version. I will be really thankful if you help me in finding out what sort of mistake is my code having.

try this:
import grails.core.support.GrailsApplicationAware
import grails.core.GrailsApplication
import grails.web.mapping.LinkGenerator
class MyService implements GrailsApplicationAware{
GrailsApplication grailsApplication
def config
LinkGenerator grailsLinkGenerator
def myMethod() {
def url = hostname+grailsLinkGenerator.link(controller: 'someController', action: 'something', params:[token:something], absolute: 'false')
}
void setGrailsApplication(GrailsApplication ga) {
config = ga.config
}
}
...
String hostname=grailsApplication.config.myApp?.hostName
def url=hostname+grailsLinkGenerator.link(controller: 'someController', action: 'something', params:[token:something], absolute: 'false')
or
def url=grailsLinkGenerator.link(controller: 'someController', action: 'something', params:[token:something], absolute: true)
ED2A
If you must
I have applicationTag lib working this way:
import grails.util.Holders
import org.grails.plugins.web.taglib.ApplicationTagLib
class SomeService {
def g = Holders.grailsApplication.mainContext.getBean(ApplicationTagLib)
def someMethod() {
def aa = g.createLink('something')
}
}
The problem with doing things this way is if you start hitting presentation layer references then you may get No thread-bound request found. Specially from quartz jobs and anything that is called outside of the scope of a real user. You can get around all of this using this example. But why go through all that when the grailsLinkGenerator example above won't hit any of the issues that may arise otherwise

I came here because I just wanted a link created in a regular service class, and V H's answer^ helped me; thank you! :D
But for those looking for the same thing I was, this is what is sufficient for us to work (Grails version 4.0.4):
import grails.web.mapping.LinkGenerator
and in the service method:
def link = grailsLinkGenerator.link(
controller: 'controlerName',
action: 'actionName',
params: [uuid: "uuidExample"]
)
Thank you once more, V H! :)

Related

django rest framework save serializer fail with post method

I'm trying to update a profile object with post method, but I get a error message when trying to save my serializer :
You cannot call `.save()` after accessing `serializer.data`.If you need to access data before committing to the database then inspect 'serializer.validated_data' instead.
My view :
class SettingsProfileView(APIView):
"""
Get and update user profile
"""
queryset = models.UserProfile.objects.all()
serializer_class = serializers.UserProfileSerializer
renderer_classes = [TemplateHTMLRenderer]
template_name = 'base_/settings/profile.html'
def get_object(self, pk):
try:
return models.UserProfile.objects.get(pk=pk)
except models.UserProfile.DoesNotExist:
raise Http404
def get(self, request, format=None):
if not request.user.is_authenticated:
return Response({"error": _("User is not connected")}, status=status.HTTP_511_NETWORK_AUTHENTICATION_REQUIRED)
try:
profile = request.user.profile
except models.UserProfile.DoesNotExist:
profile = models.UserProfile(user=request.user)
profile.key_name = request.user.username
profile.save()
profile = self.get_object(request.user.profile.id)
serializer = serializers.UserProfileSerializer(profile)
return Response({'serializer': serializer, 'profile': profile})
def post(self, request, format=None):
serializer = serializers.UserProfileSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
The error occured in this part : serializer.save() in my post method. Is it because the serializer is accessing data in his instentiation method ?
My serializer is very basic, it has no special code :
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ('user', 'coachs', 'is_coach', 'gender', 'weight', 'height', 'visibility', )
Maybe the problem comes from the fact that I'm using post methode instead of update ?
EDIT (after #pleasedontbelong post) :
I've tried with generic view :
class SettingsProfileView(generics.GenericAPIView):
but the update method is not fired (because I come from a HTML post), so I had to manually raise update method like that :
def post(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object(request.user.profile.id)
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response(serializer.data)
But the error is still the same.
I cannot find any example where an object is updated with django rest by post method. Is it because it's not a good way to proceed ?
After hours of debugging, it appear that the problem comes from Visual Studio's breakpoints. After removing breakpoints it works fine.
Maybe Visual Studio try to read in serializer.data and then affects them.
It's better to use generic views, it prevents you from rewriting all this code. But if you rather do it manually, you can always check the source code to check how it's done:
https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/mixins.py#L61-L78
class UpdateModelMixin(object):
"""
Update a model instance.
"""
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response(serializer.data)
def perform_update(self, serializer):
serializer.save()
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
you must pass the UserProfile instance to the serializer
BTW: you should/must use PUT or PATCH for updating, POST is for creating objects.
Hope this helps :)

Model in Grails Controller Tests is Null/Empty

I recently created a new controller in a pretty big app, (note: we just upgraded from Grails 2.0.3 to 2.3.7) and the created tests have all been failing inexplicably. Most of my errors consist of the model being [:] after a controller call. And therefore any methods on that model being null. I get stuff like:
groovy.lang.MissingMethodException:
No signature of method:
TransitionController.save() is applicable for argument types: (Transition)
values: [null] Possible solutions: save(), wait(), show(), any(),
wait(long), raw(java.lang.Object) at TransitionControllerSpec.Test the
save action correctly persists an instance(TransitionControllerSpec.groovy:45)
I have tried explicitly assigning the model by doing:
def model = controller.delete()
def model = controller.update()
//....
But I get the same result, an empty model map and null values if I try to access it.
As per this article (https://jira.grails.org/browse/GRAILS-8462) I could also try accessing the model by doing:
def model = controller.modelAndView.model
But this did not work for me either, producing the same results.
Any ideas on what might be happening?
Edit: Here are the first couple of tests
package com.hey.how.are.ya
import grails.test.mixin.*
import spock.lang.*
import org.junit.*
#TestFor(TransitionController)
#Mock(Transition)
class TransitionControllerSpec extends Specification {
def populateValidParams(params) {
assert params != null
params['reason'] = 'just cuz'
}
void "Test the index action returns the correct model"() {
when:"The index action is executed"
controller.index()
then:"The model is correct"
!model.transitionInstanceList
model.transitionInstanceCount == 0
}
void "Test the create action returns the correct model"() {
when:"The create action is executed"
controller.create()
then:"The model is correctly created"
model.transitionInstance!= null
}
//...grails generated tests here
}
Edit: Here's an interesting case! If I do:
void "Test the create action returns the correct model"() {
when:"The create action is executed"
def model = controller.create()
def inst = new Transition()
println "${model}"
println "${model.transitionInstance}"
then:"The model is correctly created"
model.transitionInstance != null
}
Then I get this as output:
[transitionInstance:null]
null
But the test passes. This only happens with create. What is going on??
Edit: Adding code for create and save
def create() {
[transitionInstance: new Transition(params)]
}
def save() {
def transitionInstance = new Transition(params)
if (!transitionInstance.save(flush: true)) {
render(view: "create", model: transitionInstance: transitionInstance])
return
}
flash.message = message(code: 'default.created.message', args: [message(code: 'transition.label', default: 'Transition'), transitionInstance.id])
redirect(action: "show", id: transitionInstance.id)
}
Edit: I can't spend too much time on this, but I'm pretty sure the problem is discrepancies between the controller generated and the test created. For what it's worth I was running version 2.0.2 of the scaffolding plugin and grails 2.3.7. I'm gonna throw out the tests created by the command and start from scratch, thanks for the help!
I had the same issue but solved it like following:
Inside the controller method:
render view: "_myTemplate", model: [instance: myInstance]
So the controller, still renders the template and inside the test spec I can test
assert(model.instance = myExpectedInstance)

How to render the output of my action

My controller:
def getMenuItemCount(String name){
def myCount = MenuItem.countByMenuItemCategory(name)
render myCount
}
What do i call in another gsp so that myCount appears. createLink doesnt seem to work
${createLink(action:'getMenuItemCount', params: [name:ci.name])}
A model has to be returned instead of rendering it in order to access it in a gsp.
def getMenuItemCount(String name){
[ myCount: MenuItem.countByMenuItemCategory(name) ]
}
Also, (not related to question really), try to avoid using action names as get* and set*. I have seen discrepancies with that nomenclature.

Is there a way to set the default namespace with Savon::Model?

Savon is stubborn in generating SOAP envelopes from WSDL's. It does it improperly and I see no way to fix it. It also takes the liberty of inserting the wsdl: namespace on everything for whatever reason.
The request I am building uses the tns: namespace. I'd love to be able to use Savon::Model, but right now I have to do:
client.request :tns, :function_name do
soap.body = { params }
end
Instead of something like:
super(params)
Making the request block in every function is tedious, and I have to define the function name every time instead of Savon automatically calling the correct function like what would happen in the ideal case. Right now my functions are looking like
def foo
client.request :tns, :foo do
...
end
Having to say "foo" twice seems ridiculous. Is there a way to set the default namespace for every request in a class that extends Savon::Model?
client = Savon.client do
wsdl "blah blah"
element_form_default :qualified
namespace_identifier :tem
env_namespace :soapenv
end
I am not sure if I understand your questions. I assume you are asking how to set the default namespace and wrap the request body in a function, so you don't need to write the request body every time. This code works for me, but I removed some irrelevant parts
class ExampleWS
EXAMPLE_WS_DEFAULT_NAMESPACE = "urn:example:request:1.0.0"
......
def getStockPrice( locale, stockId )
response = $client.request :get_stock_price do
soap.input = [
"ns1:getStockPrice",
{
"xmlns:ns1" => EXAMPLE_WS_DEFAULT_NAMESPACE #set default namespace here
}
]
soap.body = {
"locale" => locale,
"stockId" => stockId
}
end
end
......
end
......
# call the function
getStockPrice("en_US", 123 )
This works for me. It uses Savon 2, though:
class Soapservice
extend Savon::Model
client wsdl: "http://example.com?wsdl", env_namespace: :tns,
operations :get_resource, :put_resource
def :get_resource(id)
super(message: { id: id })
end
end
service = Soapservice.new
response = service.get_resource(1) #overwriting get_resource
# or
response = service.put_resource(message: { username: "luke", secret: "secret" })
(My example builds on the one from the official savon homepage)

Spring Security Plugin Authentication Failure Issue

EDITED HEADER: more related with the actual problem
I'm trying to setup spring security for my test application
i installed the plugin , created User and Role classes ;
put this to UrlMappings.groovy;
"/login/$action?"(controller: "login")
"/logout/$action?"(controller: "logout")
then I put a user in the bootstrap as follows,
import org.project.auth.Role
import org.project.auth.User
import org.project.auth.UserRole;
class BootStrap {
def springSecurityService
def init = { servletContext ->
def userRole = Role.findByAuthority('ROLE_USER') ?: new Role(authority: 'ROLE_USER').save(failOnError: true,flush:true)
def adminRole = Role.findByAuthority('ROLE_ADMIN') ?: new Role(authority: 'ROLE_ADMIN').save(failOnError: true,flush:true)
def adminUser = User.findByUsername('admin') ?: new User(
username: 'admin',
password: springSecurityService.encodePassword('admin'),
enabled: true).save(failOnError: true,flush:true)
print User.count()
if (!adminUser.authorities.contains(adminRole)) {
print "TEST"
UserRole.create adminUser, adminRole,true
}
}
def destroy = {
}
}
this print User.count() returns 1 so i know the user is created , print "TEST" works as well so i know that it goes into the if block but when i run the server it fails with
Sorry, we were not able to find a user with that username and password.
I use Grails 2.0.0.M1 , do you think it might be the issue?
The User domain class in the 1.2 version of the plugin encrypts the password for you. So older code like this that uses the springSecurityService double-encodes. Change password: springSecurityService.encodePassword('admin') to password: 'admin' and it should work.
If not, turn up the debugging and you should see a message about why it's failing. Add this to Config.groovy in the log4j block:
debug 'org.springframework.security'
Also to be safe I'd change
if (!adminUser.authorities.contains(adminRole)) { to if (!UserRole.findByUserAndRole(adminUser, adminRole)) {
`
I ma facing the same problem but after some searching came across this. http://jira.grails.org/browse/GPSPRINGSECURITYUI-33
and http://jira.grails.org/browse/GPSPRINGSECURITYUI-27
Hope this helps. But i am unable to find the next stable version where this problem is fixed.

Resources