Calling REST index action from Dashboard - ruby-on-rails

Hello Everyone I have a model 'Project' in my rails application which is a REST resource.
I also have a non REST controller 'home' with a method 'dashboard'.
I want the dashboard to render all the Projects. This means, I need to call index action on Project. There are two ways I can think of for doing this:
1.
Have a link_to to Project#Index in my dashbaord template, then as both
dashboard and Index share same layout, user can see list of Projects.
However this needs an extra click.
2.
As all other view elements for Dashboard lie in the layout file, I
could manually set the #projects instance in dashboard action and
render the index template.
This also looks like a wrong way to approach things.
What I have two models 'Project' and say 'Cookie' and I want to list them all in my dashboard? How to go about implementing it in the neatest way possible?

class HomeController < ApplicationController
def dashboard
#projects = Project.all
#cookies = Cookie.all
end
end
In your views/home/dashboard you represent those collections as you need.
If you have a partial in your views/projects/ directory, that is currently used within the projects index action to render the project collection, then you can use that view in your dashboard by calling something like:
<%= render partial: 'projects/list', locals: { projects: #projects } %>

Sounds like in your ProjectController's dashboard method you should be calling something like
projects = Project.find_all
then rendering projects in your corresponding view.

Related

Best way to create views based on a theme

I need to create separate view pages for a controller that I have.
I have a CustomerController that, based on the customer I need to create custom pages, these pages have to be stored as a file not from the db.
So normally I would have this:
class CustomerController < ApplicationController
def show
#customer = Customer.find(param["id"])
end
end
And the views would be located at:
/views/customer/show.html.erb
What I want to do is have the view pages like:
/views/customer/1/show.html.erb
/views/customer/2/show.html.erb
/views/customer/3/show.html.erb
How can I reference the specific view pages to load from within the action?
Is there a way to just pass the value 1,2,3 to the view folder path?
You can specify a template to render in the show action. Rails, without you explicitly calling render, will render the template that corresponds to that specific action...so, in your case, it will automatically render customers/show.html.erb (Note: Your controller should be plural...ie CustomersController, not CustomerController)
To override this, you can do something like this
def show
#customer = Customer.find(params[:id])
render "customers/#{#customer.id}/show.html.erb"
end

Rails filter product listing based on attribute in controller

Rails newbie here. This specific question has probably been asked before, if not here then on some other site, but after looking around a lot I wasn't able to find anything helpful because I lack the terminology to describe what I want to accomplish. I'm sorry if it comes across as trivial.
Basically I have a freshly created Rails project with a scaffold Item (generated by rails g scaffold Item [...attributes...]) and I want to create an additional page, similar to the index page, but instead of displaying all of the items I want the items to be filtered. So for the index page the part in the controller file looks like this
def index
#items = Item.all
end
and I want to know how to, instead, have some sort of controller for my other page (call it index2) that uses some find-like method only grabs the Items that have a certain attribute, e.g. are "red" in color:
def index2
#items = Item.find(color: "red") #all items that have red as their color attribute
end #are assigned to #items
How can I do this? And where can I find more manipulations (other than all(), first, second, ...) like this? Thank you for your patience.
You can add an action to your ItemsController
def red_items
#items = Item.where(color: "red")
end
you can use where for all the filters
You will have to add a view called red_items.html.erb to /app/views/items for the controller to render automatically. If you want to use index template, then just render the template explicitly in your new action
def red_items
#items = Item.where(color: "red")
render :template => "index"
end
Here is a link to Active Record Query Interface where you can find all possible query methods

Ruby on Rails - How to manage layouts in admin interface?

I have a very simple site setup using awesome_nested_set and a single table called Pages.
I would like the ability to select different layouts in the admin when creating and updating Pages. What I envisioned is a drop down on the Pages form that allowed me to select a layout/template.
The only thing I know about layouts is you are required to add them to /views/layouts/ and specify the layout at the top of the controller. I need a way to manage layouts on a per Page basis inside the app itself.
Is that even possible? If so, can you explain on a high level how that might be done so I can have a starting point?
edit
Something like this:
You can easily change the layout at render by supplying the :layout key like so:
def some_action
#... stuff
render "some_action", :layout => "custom_layout"
end
You can also set layout to a symbol in the controller definition, and the controller will run the associated method to decide what layout to choose
class UsersController < ApplicationController
layout :decide_layout
private
def decide_layout
some_boolean ? "layout1" : "layout2"
end
end
You can also replace the symbol with a proc if you don't want the method located away from the usage. Finally, you can also call #layout in an action itself.
Assuming you have files in views/layouts called something like one_column.html.erb, two_column.html.erb, etc., and an attribute called layout on you page model, you could just do:
def show
#page = Page.find(params[:id])
render :action => "show", :layout => #page.layout
end
Is that what you're looking for?

Identical Files behave differently due to link with controller

I am building my first app with ROR and stumbled upon a couple of problems due to my understanding of the MVC
I have a page to add a new item, and this works fine, rails magically hooks it up to the items controller and somehow by magic it knows to look in the method 'new' as the page is called new.
But this layer is confusing me, as i need to now create a different version of new, same functionality but with a different look so to use a different layout to application.html.erb
So i attempt to create a copy of new.html.erb and create bookmarklet.html.erb - both contain exactly the same code: a link to a form. but of course bookmarklet will error on me because it does not have that link in the controller - how do i 'wire' up bookmarklet so that i can call the new method and so that it can behave in a similar way to the identical new.html.erb
Also, how can i tell the new bookmarklet.html.erb to ignore the application.html.erb and get its layout from another file?
thanks in advance
The magic happens in the routes. Rails uses something called RESTful routes, which is taking HTTP verbs and assigning standard actions to it. the new action is a GET request in HTTP speak, and if you are using scaffolding or following REST, will have the ruby call to build a new object in the controller, as an instance variable so you can use it in your view.
You have to tell rails routes that you want to BREAK this arrangement and to let /items/bookmarklet be used in the controller.
In your routes.rb file replace resources :items with
resources items do
member do
get 'bookmarklet'
end
end
In your controller put:
def bookmarklet
#item = Item.new
render :template => "bookmarklet", :layout => "different_layout" # or you can put this on the top of the controller, which is my style, but whatevs.
end
You should look into partials, if you are doing this as they clean up your code immensely.
A better way to think of things is to start with the controller instead of the view html.erb files. So each public method in your controller is effectively a page or action in the site. When you need a new action or page, add the method to the controller first. Then create the relevant view files.
So in your controller you'll need something like:
def bookmarklet
#item = Item.new(params[:item])
#item.save
render :template => "items/bookmarklet.html.erb", :layout => "different_layout.html.erb"
end
Normally you don't need to call render manually in the controller, but since you want a different layout than the default you need to specify it using render.

Rails Sub-controllers?

I'm pretty new to Rails and have an issue which I can't quite get my
head around as to the architecturally 'correct' way of doing it.
Problem relates to what I kinda call sub-controllers. The scenario is
this:
I have a series of pages, on which is a panel of some form containing
some information (think the user panel on gitHub top right).
So, in my app, I have controllers that generate the data for the pages
and render out the responses which is fine, but when it comes to this
panel, it seems to me that you would want some sort of controller action
dedicated to generating this panel and it's view.
Question is, how do you go about doing this? How do I render a 'sub
controller' from within a view?
I would put the logic in a helper or a module. (http://api.rubyonrails.org/classes/ActionController/Helpers/ClassMethods.html)
Then render partials where you want these things displayed. (http://api.rubyonrails.org/classes/ActionView/Partials.html)
Like Herman said, if it's logic that you need generated after the controller hands off to the view (ie, the Pages controller generates a page view, but you want a customized panel) then put it in a helper. Or, call a separate method in your Pages controller before handing off to the view. Or, if it's a lot of logic, create a Module and stick it in your /lib folder. So you could have a whole Panel module with methods that generate different parts of your Panel and which are called by your controller. But if you want to call these methods from within the view, then you should use a helper instead.
I dont think a module is what is required here, modules are required for shared behaviour across a small subset of your classes.
What I think is required here is the understanding of the inheritance of ApplicationController and also layouts
so, for example, my layout might look like:
<html>
<head><title>Foo</title></head>
<body>
<%= render :partial => (current_user ? "/shared/user_widget_bar" : "/shared/login_bar") %>
<%= yield %>
</body>
</html>
Any code that i want to use for it would go in my ApplicationController since it would be shared across the majority of my app:
before_filter :generate_user_widget
def generate_user_widget
if current_user
#avatar = ...
#unread_messages = ...
end
end
I understand that it might be cleaner for it to belong in a separate controller BUT honestly, unless the code is huge, it doesn't matter and can even still be put inside a module which is then included by ActionController. However it does need to be inside ApplicationController if you consider the scope of it.
If there are more related pages, say for example, you have a Rails app that manages multiple sites and you want shared behaviour across a particular site, try creating a parent controller which has no actions and only private methods, any controllers that need to have access to those methods can inherit off it. That way you can apply before filters to all controllers which inherit off it, saving you the pain of forgetting to add one in your non-parent controllers.
e.g:
class SiteA::SiteAParentController < ApplicationController
before_filter :generate_user_widget
...
end
class SiteA::ProductController < SiteA::SiteAParentController
def index
...
end
end
well, if you really need to call a controller action from the view, you can use components. They were part of the framework, now they only exist as plugins. One such plugin that seems to be well maintained is here: http://github.com/cainlevy/components/tree/master
from its docs:
== Usage
Note that these examples are very simplistic and would be better implemented using Rails partials.
=== Generator
Running script/generator users details will create a UsersComponent with a "details" view. You might then flesh out
the templates like this:
class UsersComponent < Components::Base
def details(user_or_id)
#user = user_or_id.is_a?(User) ? user_or_id : User.find(user_or_id)
render
end
end
=== From ActionController
class UsersController < ApplicationController
def show
return :text => component("users/detail", params[:id])
end
end
=== From ActionView
<%= component "users/detail", #user %>

Resources