How do you handle widgets in rails? - ruby-on-rails

StackOverflow, for example, has a user's reputation displayed up top. Clearly, this is grabbed from the database, and it's displayed on every page. Of course, this isn't in every controller action on every page, because that would be incredibly redundant.
How do you handle this kind of situation in rails? The only way I can think of it is to use before_filters to pass the models into the page, but that just seems like abuse of that feature. There seems to be the cells gem that does what I want, but I'd imagine this is a common problem and there must be a simple solution for it in rails without having to resort to plugins or gems.

What you are looking for is the layout. In rails this is where you define headers, footers, and sidebars that frame your site. Look for app/views/layouts/application.html.erb in your generated rails code. Towards the bottom you will see:
<body>
<%= yield %>
</body>
The yield is where rest of the app gets invoked. Everything before and after the yield will appear on every page. So, using your example, you might query the database and set the instance variable #reputation in the application controller:
#reputation = User.find( current_user ).reputation
then display it in the layout like this:
<body>
<%= #reputation %>
<%= yield %>
</body>
This is covered thoroughly in the book "Agile Web Development With Rails". If you are going to develop in Rails I recommend getting the latest edition.

I would just make a partial with the widget in it and render it in the layout(s) where you want it to appear. Let it do whatever it needs to do, eg connect to the db, run some js to connect to an external site, etc.
If you're concerned about optimisation then deal with it when it becomes a problem.

I guess, you can put the code you need into a view helper. And then render some partial, like it was said before, in the layouts where you want it to appear, calling helper's function.
Look here:
Rails view helpers in helper file

Related

Use template to create multi-page ruby on rails web application

Is there any way to create a webpage template that I will be applying to all my webpages?
I am new to ruby on rails, I have gained enough knowledge to understand how flow works in it but can't find out the way to use the same page-template for all pages on the site.
I am using RubyMine but can work on command prompt if required.
Any help would be greatly appreciated.
app/views/layout/application.html.erb this is a common layout in which you will found <%= yield %> which render all the pages in <body> tag. Now as per your requirement you want some common template to show on all pages.
So better to make one partial file..For example, Header and Footer remains same in whole site. For doing this, make one partial file called _header.html.erb for header part and _footer.html.erb for footer part. Put these files under app/views/layout/_your_partialfile.html.erb
Then render them like:
<%= render partial: "/layouts/header" %>
<%= yield %>
<%= render partial: "/layouts/footer" %>
For more info refer : http://guides.rubyonrails.org/layouts_and_rendering.html
I hope this makes you clear to understand now. :)
In general, rails projects have a file in app/layouts/application.html.haml that's applied to every single page you load. You can put navbars there, login links, etc.

How to find where a view partial is used?

How do you go about easily finding out where a Rails view partial is used?
In what views, controllers etc.
This is handy when working on an app that someone else wrote. You don't necessarily know what views are using a particular partial, or where to find where the partial is used when navigating the app in the browser.
Currently, I am using the Sublime Text editor to project-wide search for the partial name "form" or "_form", or for "render ", but this gives an unnecessary amount of useless results.
You could try putting this caller inside the partial, and then running your test suite:
#haml
- p caller[x]
#erb
<%- p caller[x] %>
I used x because you'll have to play around with which index you're calling to get useful information.
There's no built-in solution, but I wrote a gem to try to solve this exact problem: https://github.com/Negotiatus/Partial-Finder
It's a rake task that will recurse through your project and attempt to create the full render chain (and routes!) for a given partial. Hope it helps!

Still having a hard time with RoR MVC approach

I suppose it should do justice to state what I think I know so far as well as what I've done:
1) I created the app and did my first db migration; I now have my dev, test and production databases. The dev db has a table called 'wines'.
2) I made a scaffold which created the necessary files.
3) The basic index/update/destroy methods are set up and I can browse the pages.
4) From what I gather, the ActiveRecord class "Wine" automatically inherits properties from the database? Each column is a property and each row in the table 'wines' is a potentially instantiated object which is called from the wine_controller script.
The problem I'm having now is that I want to create a common layout that all controllers use. The only things that will change will be the page title, potentially some <link> tags in the header, the <body> attributes (javascript onload events most likely) and whatever lies inside the <body> tag.
I find myself looking up functions that will do what I want (like "favicon_link_tag", "stylesheet_link_tag" and "auto_discovery_link_tag"...) but I can't find the right place to PUT them! I know this has something to do with my lack of understanding of how things are executed/inherited. For example if I were to declare #pageTitle in application_controller.rb and use #pageTitle in ApplicationHelper it won't work. Or even using "stylesheet_link_tag" in application_controller.rb throws an error. I'm just not getting something.
How does each thing relate to another in terms of chronological execution, scope, etc.?
In your "app/views" directory there is a folder called "layouts." By default there should be an "application.html.erb" file in there, but if there isn't you can create it.
Your "application" layout file is the default layout file used by any view. However, if you want a particular controller to use a different view, you can override this. See this railscast, and this one is helpful too.
The main thing to understand is the content from any particular view will show up wherever the yield method appears in your application layout. The main 'yield' block gets the view file specified by your controller action, but you can mark anything inside any view to be passed to another yield block instead. For instance, the "title" example you gave could be passed to the head of your application layout. See this railscast for a detailed example of that.
For more, you should read the Rails Guide, and you might want to consider picking up a Rails starter book.
I got my feet wet with "Beginning Rails 3," which was a phenomenal introduction to the framework. A couple days with that book and it was all making sense to me, and I was developing faster than I ever had before. Rails rocks once you get to know it, but it's definitely worth going through a book.
Please continue to ask questions, I'll help if I can :)
-EDIT- To answer your question about control flow, it basically works like this:
Your browser sends a GET request for a particular URL.
The router takes that request, matches it to a controller action, triggers that controller action, and provides the controller any parameters associated with the request. For instance: if you requested example.com/posts/123?color=red this would trigger the SHOW action of your posts_controller, and would pass {:color => 'red'} to the params hash. You would access that using params[:color]
The controller action does its thing, and when it's done it renders output. By default it renders whatever view is located in app/<controller_name>/<action_name>, and will whichever file matches the extension appropriate to the request (ie an AJAX request would trigger <action_name>.js.erb and a GET request would trigger <action_name>.html.erb.
You can override this using the render method, for example by passing render 'foo/bar' to render using the view for FooController, Bar action instead of your current action.
Note that no matter what you render, the data available to the view is whatever is in the specific controller action the router triggered, not the controller action that would 'normally' render that view.
The view file is parsed using the data from the controller that called it. If you have any content_for methods then the view code that is inside the content_for block will go where you tell it, otherwise everything else will go to the main YIELD block in your application layout (or whatever layout your controller specified instead).
The application layout is parsed, and the content from the view is inserted into the appropriate areas.
The page is served to the user.
That's a simplification in some ways, but I think it answers your question. Again, feel free to keep asking :)

What are the best practices to generate "widgetized" content in Rails

On my previous projects built with usage of Zend Framework I extensively used Zend_view's "Action View" helper. It basically allows to initiate a separate cycle of request->dispatch ti action->view_rendering from a view script.
Here is the link to an appropriate page of zend framework reference guide (search for "Action View Helper").
This helper is quite a convenient way to work with widgetized content for example on pages with portal layout where you can stuff a page with different widgets (like advertising blocks, currency informers etc).
Although such an approach negatively affects response time of the page as it involves a lot of additional routing/dispatching activity, it allows to organizes widget code and views scripts into a rational structure. One widget is just a controller action, with linked view script.
Unfortunatelly, I have not found any similar view helpers in Rails.
Is there any way to elegantly solve this task in Rails?
In Rails, the render method of ActionController takes a Hash as arguments and outputs a simple string. You can use this in your view like so:
<%= render :partial => "shared/widgets/_#{widget.widgettype.name}", :collection => #current_user.widgets %>
In this case Rails will iterate through the list of #current_user.widgets, find a widget partials in "app/views/shared/widgets/_widgettypename.html.erb", and call the partial for each attached widget.
For further reading on Rails partials, see the ActionView::Partials documentation.
It seems that I've found an answer to my questions myself. It is "render_component" rails plugin. There is also a fork which apparently supports Rails3.

In Rails, is there a way to selectively load files in the view from application layout?

So in my Rails application, I'm trying to set up Javascript testing on certain views.
Right now, I'm doing this by having a conditional in each view..
<% if AppConfig['js_testing'] %>
<script>
...
</script>
<% end %>
If I have it on each page, there's a lot of code duplication. Is there a way manage everything from the application layout?
There's a few places you can put this that will help reduce duplication. The main layout is an ideal candidate. Another possibility is a helper method that's a lot easier to introduce.
You could also define a conditional javascript_tag helper method that will only introduce the JavaScript if your trigger is set. Usually this is along the lines of:
def javascript_testing_tag(content)
AppConfig['js_testing'] ? javascript_tag(content) : ''
end
Then it's a pretty straightforward exercise to wrap all your test scripts with that conditional. It will make it easier to refactor things later should the logical trigger for this behavior change.
The optimal implementation depends on what kind of scripting content you're introducing. If it's tied closely to the JavaScript that may be on a particular view, you may be stuck doing this.
An alternative is to simply tag each page and have a testing JavaScript harness that will trigger specific behavior depending on the structure of the document. For example, if there's an element div#user_list you might run testUserList().
It is then trivial to simply not include the testing JavaScript file in non-testing environments.

Resources