dynamic data included in application.rhtml?

I'm going to preface this by saying that I'm a total Rails newb. I'm learning via books and tutorials, which is great, but I keep getting hung up on something I'm sure is totally simple, but I just can't quite figure out how to do, and is rather essential to my being able to feel like I'm getting somewhere and moving along with it all.

That said. I'm looking to include a few different bits of database data in my main application template. I can get the views looking the way I want them using a regular controller & view, but can I then include this view in my application.rhtml, or does it need to be written as a partial? And can I even have two controllers using the same model? Or should this whole thing be written directly into the application template, or as a component? I'm just not sure how to approach it all, which is a little frustrating since I'm used to using PHP to develop my websites, and doing this in PHP would be a rather straightforward effort.

Can anyone guide me in the right direction?

Thanks!

sarah

Sarah,

I'm not sure I understand your question, but let me give you my approach. I use the application.rhtml to contain things that are universal across my application. I include a lot of dynamic data, but only class variables that are universal as well. Then all of my views are just the contents of page, while the application.rhtml wraps the whole page up. Wow. I'm not sure that made sense.

Controllers are totally independent of models; they just interface the user to the models. So you may have a login controller that references the user model.

I hope this helps! Maybe try posting up something more specific...

--Tom

Well, what I'm trying to create is this:

http://clients.triggersandsparks.com/new/template.html

where the various controllers' output would be rendered in the "content" div (where the headline & lorem ipsum is).

Below that is a horizontal bar (which I'll call the "portfolio bar") with two different sets of database data, to be displayed as part of the app template.

A simplified view of how the data would be grabbed & used in the portfolio bar:

To the left, a single record with a specified ID from the "feature" table would be displayed.

To the right, all records from the "projects" table would be displayed. The "projects" table will also be used as its own controller -- ie, full project details (along with corresponding data from the "images" table) would be displayed in the content pane when invoked by an action (probably "show").

I can build a "feature" model with an index action & corresponding view to display that part. I can also build a "project" model with a list action & view to display the list for the portfolio bar.

Essentially, my questions are:

1. How do I include those views in my application.rhtml? Can I just include them as I would a partial?

2. Should I create a show action & view for the "project" model to display the project data in the content pane, or should this use a seperate controller?

I'm going to do a little searching about class variable, and see if that doesn't clear things up for me a little.

Thanks for the input, and I hope that makes my question a little clearer!

Hi Sarah,

sarah wrote:

That said. I'm looking to include a few different bits of database data in my main application template. I can get the views looking the way I want them using a regular controller & view, but can I then include this view in my application.rhtml, or does it need to be written as a partial?

Depends on what you're trying to accomplish. If you include the code in application.rhtml it will appear on every page your app serves (barring the use of conditional logic, which is also ok). Partials have broader uses, but are also useful for reducing redundancy.

And can I even have two controllers using the same model?

Yes.

Happy to answer more specific questions given more detail on your objectives.

hth, Bill

So I can include Ruby code that takes data from .... the controller? ... in my application.rhtml? I'd definitely want it to appear on every page (see the post above for more details re: what I'm trying to do), and wouldn't need to reuse the code anywhere else. This would probably be a lot easier if I had a better grasp on basic MVC concepts, which I'm trying to gain, but again, my process requires a lot of learning-by-doing otherwise all the theory just vanishes. I think I'm going to have to sort of jump into it & see what works, and what doesn't.

sarah wrote:

So I can include Ruby code that takes data from .... the controller? ... in my application.rhtml?

Yes.

This would probably be a lot easier if I had a better grasp on basic MVC concepts,

I also wasn't sure, from reading your other post, that you fully grasp the basic difference between a Rails application and a web site with mostly static pages livened-up with some PHP scripting.

which I'm trying to gain, but again, my process requires a lot of learning-by-doing otherwise all the theory just vanishes.

Definitely. Have you worked through any of the tutorials out there? It's worth your while if not.

Best regards, Bill

I've done the Rolling with RoR tutorial. I'm in the midst of RoR: Up and Running, which is helping, but I'm not sure it's going to teach me what I need to know. I started in on Rapid Web Development with RoR, but I really need something that I can apply to what I do a little faster.

Usually, the websites I build aren't apps per se. The content is all contained within mySQL databases, and I think I've a decent grasp on how to correctly design my database relationships, and I do tend to make use of these. Everything's custom-built to a clients' specifications so I end up repeating a lot of database queries, and there's always a backend to perform all the various CRUD functions. I'm pretty sure that, though none of this mandates a full-fledged web app, using RoR would definitely speed my production time. The portfolio site referenced above is definitely the simplest of projects I tend to undertake, and I'd really like to be able to produce better/stronger/faster CMSes (which is essentially what they are) for my clients.

I recognize that PHP is just a scripting language, whereas Ruby is a full-fledged programming language (and both OO programming and the use of frameworks are rather new to me), however, it seems like I'm either missing something very simple and vital or like I'm approaching it entirely the wrong way. Since my websites are usually very database-dependent, I think RoR would really make everything a lot cleaner & better -- I just wish I knew why my brain can't wrap around everything better. I've read and absorbed and tried so much, but it seems like the moment I try to step beyond the scope of the basic tutorials in order to create my own programs, things become confusing. Is this common, or am I just being too impatient with myself?

(It feels rather like the difference between learning the clarinet and the guitar ... if it makes sense, I could learn the clarinet because I could play things instantly. The guitar, well, I'd learn a few chords, then try again later, and it'd all be lost, and I'd have to start over again.)

I feel like I'm whining & ought to stop. This is helpful in that it gives me an idea of where I ought to be going. I guess a better question might be this:

Since most of the tutorials I've seen leave the actual "connection" to the controller as implicit (ie controlller.rhtml knows to access controller methods), how would I tell application.rhtml to grab data from such-and-such a controller? That, I think, would be a HUGE help.

Thanks for all your feedback.

Hi Sarah,

sarah wrote:

I've done the Rolling with RoR tutorial.

<snip more good stuff demonstrating good-faith efforts prior to asking for help :wink: >

Usually, the websites I build aren't apps per se. The content is all contained within mySQL databases it seems like I'm either missing something very simple and vital or like I'm approaching it entirely the wrong way.

Potentially both. It was for me, inasmuchas the led to the second. When I got the switch flipped, it all became amazingly intuitive.

I'll try to help by relating my personal experience.

In my past (fairly limited) web-development experience the point-of-reference was the web pages. They existed. They contained and/or called scripts that provided content to 'fill in' the web pages.

For me, the a-ha moment came in recognizing that this is Not So in Rails.

In Rails the point-of-reference is a controller and its methods. They, not the pages they generate, exist independent of user actions. In Rails, web pages are generated as one of the last activities in a request-response cycle. The rhtml views/layouts are just 'helpers' that Rails uses to fulfill the request to return an html page, a piece of a page, or some javascript to execute. So the question I learned to start with in Rails was different. It's not, "what data do I ask for to put in this page?" It's "what page do I want and which is the best method / controller to ask for it?"

Since my websites are usually very database-dependent, I think RoR would really make everything a lot cleaner & better --

It's almost guaranteed.

I just wish I knew why my brain can't wrap around everything better.

"It's not what we don't know that hurts. It's what we know that ain't true." Will Rogers

I've read and absorbed and tried so much, but it seems like the moment I try to step beyond the scope of the basic tutorials in order to create my own programs, things become confusing. Is this common, or am I just being too impatient with myself?

I think it's common.

(It feels rather like the difference between learning the clarinet and the guitar ... if it makes sense, I could learn the clarinet because I could play things instantly. The guitar, well, I'd learn a few chords, then try again later, and it'd all be lost, and I'd have to start over again.)

Interesting analogy. I think there is definitely a 'natural affinities' component in our choice of development tools. I've noticed that most of the folks who really like Rails have a programming background. You?

how would I tell application.rhtml to grab data from such-and-such a controller?

You wouldn't. You'd ask a controller method to render a page, some of which gets rendered using application.rhtml rather than a controller-specific view. Now that I've got a little better handle on 'where you're coming from' I'll go back and take a look at your explanation and try to be helpful with specifics.

Best regards, Bill

Hi Sarah,

where the various controllers' output would be rendered in the "content" div (where the headline & lorem ipsum is).

OK. But you're obviously thinking about this from the 'I have this page and I want to change a part of it.' Another way of thinking about it would be 'where the difference between the pages that get generated is the content of the "content" div.' It's small. Probably seems 'nit-picky'. But it'll make a difference.

Below that is a horizontal bar (which I'll call the "portfolio bar") with two different sets of database data, to be displayed as part of the app template.

This looks to me like a menu / nav bar. If that's the case then it very naturally gets handled in the application.rhtml layout. The question becomes how best to feed it the data it needs.

A simplified view of how the data would be grabbed & used in the portfolio bar:

This, and what follows, confuses me.

To the left, a single record with a specified ID from the "feature" table would be displayed.

The page you sent us did not show what appeared to be a record (or it's contents) but rather a link to a record. When I click the 'see more' link it looks like the intention is to display some new content in the 'content' div. Is that right?

To the right, all records from the "projects" table would be displayed.

The mockup shows images and a 'more' link for what looks like 3 categories of projects. The images are links. What happens when one is clicked? What happens when the 'more' link is clicked?

The "projects" table will also be used as its own controller --

No offense intended here, but this statement really underlines a need for further study on the MVC basics.

Essentially, my questions are:

1. How do I include those views in my application.rhtml?

Copy / paste.

2. Should I create a show action & view for the "project" model to display the project data in the content pane,

Terminology aside... yes. The project _controller_ should have a 'show' action which will be rendered using the 'show.rhtml' view which will be wrapped in the application layout and then sent back to the browser in response to the visitor clicking a link to a particular project.

I'm going to do a little searching about class variable, and see if that doesn't clear things up for me a little.

Maybe, but I'd be surprised.

The main issue seems to me to be about the choice of how you feed the data needed in your 'portfolio' nav bar. There are a number of options. There is one thing that jumps out at me that could make the choice simpler. Do you really need a 'feature' table (that needs to be named 'features')? Or is the thing being featured just a project that already exists in the 'projects' table that could be identified by setting the value of a 'now_being_featured' field? Either way, you don't have to have a controller for each model. You can access all your models from a single controller if you want. Probably makes some sense in this case.

hth (and feel free to continue the conversation if you like), Bill

Hi Bill,

You're being insanely helpful, and I really appreciate it. I've been doing some more (re)reading of MVC concepts. I think part of the reason I keep getting lost is because I'm -- for starters, more a designer than anything else, and I sort of picked up PHP in order to start building database-driven websites. But I really DO want to do it right. I know I'm mixing my terminology left-right-and-center .... tonight I'm going to try to compile all my notes into logical cheatsheets to help me figure out what goes where and what does what, which I'm hoping will help.

OK. But you're obviously thinking about this from the 'I have this page and I want to change a part of it.' Another way of thinking about it would be 'where the difference between the pages that get generated is the content of the "content" div.' It's small. Probably seems 'nit-picky'. But it'll make a difference.

The "controller calls view" rather than "view asks for controller" switch helps a LOT in terms of my understanding -- again, this probably has something to do with how I'm used to querying the DB for data right in the middle of my PHP code. (I can see how the MVC framework cleans things up, now!).

> A simplified view of how the data would be > grabbed & used in the portfolio bar:

This, and what follows, confuses me.

> To the left, a single record with a specified ID > from the "feature" table would be displayed.

The page you sent us did not show what appeared to be a record (or it's contents) but rather a link to a record. When I click the 'see more' link it looks like the intention is to display some new content in the 'content' div. Is that right?

The idea was to have a "feature" table with an image, some text, and a link to the project_id. Ideally I could work it to the point at which I could have more than one, and display them at random (from the PHP mindset, I'd just count the rows, generate a random number between 0 and numrows, then grab & display the image, link, and text for the given ID). But again, I'm thinking about this backwards, which is maybe the problem. I assume the randomization would need to occur in the controller, rather than the view?

The mockup shows images and a 'more' link for what looks like 3 categories of projects. The images are links. What happens when one is clicked? What happens when the 'more' link is clicked?

When an image is clicked, it would render the page for the project data. Each project would contain a title and text, and would be described as having many images, each with its own filename, title, and text. I'm given to understand that, so long as both models describe this data relationship (Image belongs_to :project and Project has_many :images), I can create a single controller with an action to display this data.

Terminology aside... yes. The project _controller_ should have a 'show' action which will be rendered using the 'show.rhtml' view which will be wrapped in the application layout and then sent back to the browser in response to the visitor clicking a link to a particular project.

This makes sense.

And, from my understanding, the application.rhtml is basically a bunch of static stuff wrapping a <%= yield %> snippet. Which will work for everything except for the menu bar stuff.

Barring the "featured" bit for the moment, how do I tell the project controller to render a 'list' action in the menu bar area, regardless of what other controllers and actions are being called elsewhere in the app?

I know you can use the yield code to show an ... (instance?) variable, but can it be used to show the contents of an action?

At any rate, I'm going to try some more fighting with this this evening, and hopefully I'll be better equipped to figure out how to do this.

Thank you SO MUCH for all your help .... it helps me feel like I WILL get there, eventually.

s

Hi Sarah,

sarah wrote:

You're being insanely helpful, and I really appreciate it.

You're welcome.

I think part of the reason I keep getting lost is because I'm -- for starters, more a designer than anything else,

You might be sorry you let that slip :wink: There are a bunch of us, including me, that need design help.

.... tonight I'm going to try to compile all my notes into logical cheatsheets to help me figure out what goes where and what does what, which I'm hoping will help.

I'd bet on it.

The "controller calls view" rather than "view asks for controller" switch helps a LOT in terms of my understanding

Good deal. At the risk of 'nit-picking', that's an improvement but still a bit short. The controller doesn't really 'call' a view. Not in the sense that, for example, a controller method might 'call' a function. How does 'controller yields to view' strike you? Rendering is the thing that happens _after_ the controller is finished. When the controller is done, Rails takes the values of the instance variables that the controller has made available and uses them to fill in the view templates to render a page.

I assume the randomization would need to occur in the controller, rather than the view?

You could certainly do it with JS on the client (which is what I think you're talking about) but I don't see the value in messing with that here. I'd do it in the controller.

Barring the "featured" bit for the moment, how do I tell the project controller to render a 'list' action in the menu bar area, regardless of what other controllers and actions are being called elsewhere in the app?

I think it'll be better to wait til you've put your cheat sheet together to answer this. The thing is, your thinking is not that far off if you were ready to tackle Ajax on Rails. I'm sure it's tempting to want to go there, but things will go a lot more smoothly for you if you start with basic full-page rendering. For now, think about the question like this. "How do I tell Rails to send me a page that has all the right stuff on it, including in the menu bar area?" Try playing with this code to start off.

--- project_controller.rb --- # the project model doesn't need to be explicitly named in the project controller def index   the_one = 1 # just for testing until you code the randomizer, of course   @this_weeks_feature = Feature.find(the_one)   @projects = Project.find(:all) end

--- index.rhtml --- <p>Just to prove you were actually using the index view...</p>

--- application.rhtml --- In addition to the usual stuff.... <div id="featured">   <%= link_to "see more", {:action => show_feature, :id => @this_weeks_feature.id}%> </div>

<div id="project_list">   <% @projects.each do |this_project| %>      <p><%= link_to this_project.name, {:action => show_project, :id => this_project.id} %></p>   <% end %> </div>

I'll look forward to hearing from you again tomorrow.

Best regards, Bill

Hi Sarah,

Seems Bill is doing a good job of describing the concepts, but I thought it may help to hear from another person learning Ruby and Rails.

My background is in network support, with a few websites developed on the side mainly in PHP. So I feel your pain. Stick with it as the results are great. Rails provides what I had always wanted PHP to do for me - seperate the content from the logic from the layout (MVC). When the penny drops a whole new world will open up for you :slight_smile:

Here's how I think of Rails:

1) A request comes in from the user - say http://mysite/projects 2) Rails uses the defined routes (config/routes.rb) to workout how to divide up the request and what to do with it. The default is ":controller/:action/:id" which means the first part of the request will be the controller's name followed by a "/", then the action's name followed by a "/" then the id. 3) Rails looks for a file called app/controller/projects_controller which should define what do do when a user requests one of these pages. 4) If no action is specified (as in this case) the default is "index", so Rails looks up the "def index" action and run it. The controller will then call whatever models, etc it needs to perform the task. 5) When that is done it looks for a way to display the results back to the user and goes looking for a file called "app/views/projects/index.rhtml" (this can be changed in the controller). 6) Rails renders the view, including all the partials specified etc. (Note: logic can also be placed in here) 7) To finish everything, it wraps the output of the view in the layout. By default this is "app/views/layouts/application.rhtml" Note: The layout can also include partials and logic. Note: The layout can be overridden if the controller says so, or the file app/views/layouts/projects.rhtml" exists. 8) The result is sent back to the user and we start all over again.

The upshot is that every URI needs an controller and action and view to respond to it (unless you get clever with routes). Anything in application.rhtml will be included on every page.

Buried in this flow are the MVC concepts. The model is the gatekeeper to the data. It makes sure everything going in is OK and can help to return custom data sets. The controllers respond to the requests and the views are there to render the results. This is quite different to PHP where everything is usually mixed together (this page connects to the database, runs a query and displays the results).

Hope that helps.

Andrew

Hi Andrew,

askegg wrote:

Here's how I think of Rails:

< snip one really understandable explanation >

Hope that helps.

That's very nicely said.

Best regards, Bill

I thought I ought to post a bit of an update to this. It seems like the only way to really get into Rails is to start playing and developing, and I think things are actually going quite swimmingly right now -- I'm working on design & backend concurrently, which actually seems to mesh well in RoR as well as in my particular methods of working.

The "how do I include this universally?" went down pretty easily once I figured it out. Essentially, I created the controllers to access the data from the requisite models, then coded the view templates, then moved the controllers so that they belonged to > ActionController::Base rather than > ApplicationController. Then I included the two controllers in my template by using render_controller => 'projects', action => 'thumbs'. This wasn't the most elegant solution because my 'projects' controller originally was used for two actions (thumbs/list, and show/display), and the two needed to be seperate (because show needed to be a class of AppController, while thumbs needed to belong to ActionController). Then the features controller is stuck I think in the main app controller. So it's not the most elegant way of approaching it, but I figure as I learn things I'll go back & clean everything up so it's a little more fluid. I'm getting the impression that a lot of people learn the Rails this way, since the documentation is so all-over-the-place and varied.

But I'm definitely getting excited about this! I'm really enjoying RoR and think I'll get a lot out of it, and it's encouraging to see a site almost ready-to-roll (the bulk of the work is coding, now).

I've learned how to write my own methods (in the various helpers) and the next major task on my list is figuring out how to use ActionMailer to create my "Request a Quote" web form in RoR format -- anyone seen any good resources on how to do this? I'm struggling a little with a search-and-replace method I'm trying to write for database text (essentially, all instances of "<h1>." need to be replaced by "<h1 class=".">.") but I figure I'll leave it be for the time being, and will have it figured out before long.

So again, thanks for all the help and guidance! It's encouraging that there's such a strong RoR community, and I hope to get a little more involved as I get my footing in it.

Hi Sarah,

sarah wrote:

So again, thanks for all the help and guidance! It's encouraging that there's such a strong RoR community, and I hope to get a little more involved as I get my footing in it.

Congratulations on your progress. And welcome aboard! Well look forward to your involvement.

Happy Holidays! Bill

Hi Sarah,

I've learned how to write my own methods (in the various helpers) and the next major task on my list is figuring out how to use ActionMailer to create my "Request a Quote" web form in RoR format -- anyone seen any good resources on how to do this? I'm struggling a little with a search-and-replace method I'm trying to write for database text (essentially, all instances of "<h1>." need to be replaced by "<h1 class=".">.") but I figure I'll leave it be for the time being, and will have it figured out before long.

The API documentation for ActionMailer is a good place to start:

Dave Thomas's book Agile Web Development With Rails also has good information on this.

For your search and replace, if you have your text in a string called text you can use the gsub method. For example:

text.gsub(/<h1>[.]/, "<h1 class='.'>.")

will return a new string with all instances of "<h1>." replaced with "<h1 class='.'>.". Here's some more information:

http://www.ruby-doc.org/core/classes/String.html

Hope that helps, Andy Stewart

The API documentation for ActionMailer is a good place to start:

ActionMailer::Base

Dave Thomas's book Agile Web Development With Rails also has good information on this.

Ooh, I'll check that. I have the beta book. The API doc kind of lost me. Designer brain. Needs more pictures.

For your search and replace, if you have your text in a string called text you can use the gsub method. For example:

text.gsub(/<h1>[.]/, "<h1 class='.'>.")

YES! That's exactly what I needed. The best I could get was text.gsub(/<h1>./, '<h1 class="\1">\1') which, of course, only worked the once. I didn't realize you could reference the wildcard character in the replacement string. Thank you a TON!

…except that it doesn’t work, I’m assuming because there’s something I don’t understand.

The method can’t find any instances of /

[.]/

It can, however, find instances of /

./

If I try to run

text.gsub(/

./, “

.”)

it simply returns

.

when in fact I’m looking to grab that first letter and put it in where the wildcard characters/periods are.

I’m going to look a little further into regex to see if I can’t figure out what’s up.

Hi Sarah,

Can you please show a sample of what are you expecting as a result after doing gsub.

you have ‘

Some header text

’ and expect ‘

Some header text

’ ?

This may sound a silly question but why do you want to inject a class name in an existing HTML content? couldn’t you get the same result by using a css selector for that h1 element?

Jorge

you have '<h1>Some header text</h1>' and expect '<h1 class="some_css_class">Some header text</h1>' ?

The idea is to replace it with <h1 class="s">Some header text</h1> My CSS does some stuff to make the first-letter invisible, then uses a first-letter.gif as a background for the header. So <h1>Header would render <h1 class="h">Header. I have a method defined in the AppHelper that turns h1 strings into the appropriately-tagged h1 code, and all I need to do in my templates is type in <%= header "Header String" %> and it's rendered correctly. I tried applying the header method to the replaced instances in my gsub but it told me the method was undefined. (The gsub is also a method within my app helper).

This may sound a silly question but why do you want to inject a class name in an existing HTML content? couldn't you get the same result by using a css selector for that h1 element

Technically I could manually type out the class="firstletter" for all headers, but this seems like an overly clunky way of doing it (and will be redundant when I change the template), plus users won't know to do it when modifying page contents & thus they'll get the default thing happening (Which is pretty unreadable.)

I'm wondering if I can split the string into an array based on the <h1>tags and run it through my header method then, then piece it all back together, but I was hoping that there might be a more elegant way of doing it.