We have not been able to find an example of how to do this anywhere.
It seems the way to send data from a controller to a view is using respond. Usually respond takes one argument. We want to send many.
E.g. if we have a control panel, with many different datas being displayed (users account balances, recent transactions, messages etc).
Our controller looks like this:
def index() {
User user = User.find (session.getAttribute("user"))
def accounts = Accounts.findAllByUser(user)
def messages = Messages.findAllByUser(user)
// this doesn't work, but we guess something like this might be possible.
respond [accounts:accounts, messages:messages]
}
Additionally, findAllBy documentation doesn't say what it returns. It might be an array, a map, a list.
Then in our views we should be able to do something like:
${accounts[0].balance}
or maybe
${accounts.size()}
if findBy... returns a list.
thanks to Mike W, the answer is:
def index() {
User user = User.find (session.getAttribute("user"))
def accounts = Accounts.findAllByUser(user)
def messages = Messages.findAllByUser(user)
[accounts:accounts, messages:messages]
}
Its a shame this is not in the examples in the docs, its a very useful feature
Related
I came across a post from Donal which I think was asking he same thing but did not really anwer the question, a little puzzled and wonder if possible.
If I have a tag lib, user provides controller action I Wish for it to then go off query controller and return result as a list, I tried g.include with no luck. I have tried to expand on this below but don't know too much about it and if at all possible to actually get a value back from the given primaryAction or def value within controller
if (attrs.primaryController && attrs.primaryAction ) {
//def nlist= g.include(controller:'${attrs.primaryController}', action:'${attrs.primaryAction}', id:'${attrs?.primaryId}')
def controllerArtefact = grailsApplication?.getArtefactByLogicalPropertyName("Controller", "${attrs.primaryController}")
def controllerClass = controllerArtefact?.getClazz()
def aaa=controllerClass.declaredFields.each {
it.name=="${attrs.primaryAction}" }
println "-->"+aaa.getMetaPropertyValues().
println "-------------????? ${aaa}"
}
I also thought maybe another way would be for the controller that loads up the gsp which contains the taglib should easily be able to pass a list as a variable down to the taglib, the taglib then takes attrs.newList and represents it as List.
Doing things this way the plugin was complaining about no id, really bizzare since the typical list produced from within plugin looked identical.
I have a rails app where a user can both create products and purchase products through orders.
There is a field called usermode in my usertable that sets the user to either a store_owner or customer.
IF usermode = 'Store_Owner'
I want my products index to show the products that are created by the current_user if
OR
IF usermode = 'Customer'
I want my products index to show the products purchased by a user through orders>line items>products
I am new to rails and not sure whether I need to put this logic in the model, create separate controllers, or do some kind of if statement inside my existing product controller index. I think it should go in the controller index.
How can I achieve this?
According to my opinion,
I would put the same logic in same controller. In both case (Store_Owner or Customer) you are showing the same datatype (Products). The only change b/w these two case is that your data is different. ROR is about DRY. So I think there is no need to create new view template for this. However some believe that each action in controller must represent single functionality (to reduce the clutter in controller). That means less conditional statements in controller. So you have this two choices:
I think the first one is better approach
Create single view file. write a method in model like following
def self.product_data_of(user) # The self indicate class methods
# check with if else that user is Store_Owner or Customer
# return appropriate data
end
Call this method from controller like this(I have assumed the class name is Product)
#products = Product.product_data_of(current_user)
And you can use this #products variable in view file.
Create single view file write two different methods in controller but render the same view file. In this case no need to create new method in model. But still I would prefer the previous approach.
Edit
The general way is
1) View: The logic related to how we will show will be here
2) Model: The logic related to What data or changes on data will be here.
3) controller: The logic related to the flow like fetch data from model and decide which page to render/redirect
The solution was to do something like this in my product controller:
if current_user.usermode =="Store_Owner" then
#dashboards = current_user.dashboards.active.order(:title)
elsif current_user.usermode =="Customer" then
#dashboards = Dashboard.joins(line_items: :order).where('orders.user_id' => current_user.id).all.uniq
end
Imagine a resource: /users/14/notifications. It implements several HTTP verbs/methods: GET, GET/edit, POST, DELETE.
All 4 actions share a small part of logic: retrieve all notifications, create some hash for easy access, fetch some specific user access from somewhere else to do something special etc. Just a few loc (let's say 7).
How can I reuse those 7 loc to keep the logic DRY? I've heard about Rails' ANY verb, but I have no idea how to use it. Also no idea how to use its result (a few vars) in the 4 actual actions.
I would expect something like:
def any
#notifications = Notification.find_by etc...
// do something here to create
#reverse_notifications_hash = ...
// and something else
#super_special_access = ...
end
def show
// Only specific logic here
// Render using #notifications
end
def edit
// Only specific logic here
// Render form using #notifications,
// #reverse_notifications_hash and
// #super_special_access
end
def update
// Only specific logic here
// Fetch something else special to not override stuff or be extra efficient
more_special = ...
// Do update stuff with #notifications, #super_special_access and more_special
end
As you might have noticed, I'm not a pro Ruby/Railser. (The syntax might even be wrong.) I am very curious though.
How would it actually work in RoR?
Try using a before filter to execute the common code. In your example you could add this line to your controller before_filter :any.
EDIT:
Also changed the visibility of any to private or protected so that it can't be exposed as controller action.
I have a service which returns a list of domain class objects to a controller. I'm looking for something to take pagination parameters and paginate this list like MyDomain.list(params) does. Any suggestions?
Pass pagination params to your service method. If you do pagination after retrieving objects from database (in controller in your case), your query will still return many objects you don't need and it can become a performance issue.
Otherwise if you still want to have pagination without gorm features, then you can just slice your list i.e. def sliceList = list[5..10]
Do you want the pagination to take place in your controller, or in your service?
If you want to paginate in controller, it seems easy to do:
def myList = service.listItems()
if (params.sort)
myList = myList.sort {it."${params.sort}"}
if (params.order == "desc")
myList = myList.reverse()
int from = params.offset ?: 0
int to = from + (params.max ?: DEFAULT_SIZE)
myList = myList.subList(from, to)
If you want to paginate in service (for example, to not have to fetch all the rows from the service every time), you would have to move the pagination logic there. How would you implement it is dependent of what the service does; if it fetches the data by way of SQL statements, you would convert pagination params to directives like 'limit' and 'order by', etc.
I am not sure if I am going about this the right way or not.
I have a model Neighborhood. I have a two ways you can add a neighborhood, one as a logged in user and the other as a public person. The forms vary a bit. So I made another view with a custom action. The problem is this action is adding a new record and therefore calls on "create." When it calls the create action it looks to redirect to a path that cannot exist on the public form.
Either I am doing this completely wrong or there is a way to tell my custom action to save the Neighborhood record so I can redirect on the public side.
In the create action, conditionally redirect to either the public / private page depending on the user's status:
def create
# create code goes here
if current_user?
redirect_to neighborhoods_path
else
redirect_to root_path
end
end
Or is there something that I am not understanding from your question?
i think you are saving both (public and registered users), the Neighborhood details are added to the same details. you might different this by having a user id or something
if so, As i see you can use the same controller and action. All you have to do is
identify the user like is_registred? (provided that you have a method to identify if a use is logged or not) and according to the user load layout only
Ex:
pseudo code would be
if is_registred?
render public layout
else
render registerd user layout
and you might have to check authorizations as well. Hope I understood your question
cheers
sameera