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 :)
Related
I have this webshop, and on one page you see
products;
with a submitting form for a booking;
your order with its bookings;
with a removing link for a booking;
and an updating form for a booking.
Both the order.bookings and the products make potentially long lists on a html page.
The whole booking works by only a booking_controller.
What the booking_controller does:
Takings in the (new) params of a single booking or the destroy action.
Saves the new order.
Redirects to the store.
Works fine, just using ruby and html.erb.
Only problem, and this really needs to change, is that obviously after each redirect the browser goes to the top of the page. The browser isn't focussed. Or better to say, the browser should remain, but doesn't.
I get that your doing all these things on the server-side, so a page reload, or better to say, data-refresh, is necessary. What I don't want is building this whole thing again on the client-side (JS).
Can't I simply say something like: after data refresh redirect to exact same spot on page. Ignoring all the difficulties an asynchronous request would give, or am I exaggerating and is a little JS easy?
With Rails, using ajax is very easy however if you're not familiar with ajax at all it can be a bit daunting at first. Luckily there are many tutorials on the subject. Basically, add the remote: true option to your form_for statement and rails will automatically understand you want it to make a 'POST' request in JS format. It's important to realize that the incoming HTTP request is in JS format because you'll then need to specify handling that event in the controller. Such as:
def create
#Do whatever saving and processing you need here
respond_to do |format|
format.html { redirect_to some_path_here }
format.js { } #By not adding anything in the brackets here, you're telling rails to fetch a js view file that follows standard rails convention and so it should be named 'create.js.erb'
end
Then in your controller's views folder create the view file create.js.erb. In that file you'll want to refresh whatever part of the page needs updating which usually involves hiding the old div that was there and appending a partial in its place. I usually leave an empty div with an ID on the page (in this case your new_whatever_page.html.erb that I then call in the js.erb file to append a partial to:
In your create.js.erb add:
$("#the-id-of-the-div-in-your-new-view-page").html("<%= escape_javascript(render 'order_table') %> #This basically says, find the div on the current page with a matching id and then append the partial named _order_table.html.erb to it.
Now just make a partial named
_order_table.html.erb
in the same views folder and put whatever content you want to insert or update.
Being relatively new to MVC I have been struggling for the past several weeks getting my layout to work.
I have managed to get myself really twisted into knots. So instead of trying to explain and unravel my mess perhaps instead someone could explain how I would accomplish the following at a high level.
_Layout this would have all the css js etc. It would also have basic structure.
Of course HTML tags not allowed in code block....each render is in a div.
#RenderPartial(Header)</div>
#RenderBody()</div>
#RenderPartial(Footer)</div>
RenderBody is Index.cshtml and it would be broken into three pieces
#
#Html.Partial(NavMenu, model)</div>
#Html.Partial(SubNavMenu, model)</div>
#Html.Partial(MainContent, model)</div>
I have this basic layout and it looks fine until you click one of the menu items.
The menu items render as:
<a class="k-link" href="/stuffroute">Stuff</a>
That route goes to a controller that returns a view and that navigates away from the above arrangement in Index.cshtml. So I end up with the header, footer, and subdash nav....
So the question is...
How do I route / orchestrate my layout to not lose the differing pieces?
Partials don't do anything for you here. You're essentially asking about how to create SPA (single page application), although in this case your application will have other pages, it's just that the index view will act like a SPA.
That requires JavaScript, specifically AJAX, to make requests to endpoints that will return HTML fragments you can use to replace portions of the DOM with. For example, clicking "Stuff 1" causes an AJAX request to be made to the URL that routes to FooController.GetSubNav([stuff identifier]). That action then would use what was passed to it to retrieve the correct sub-nav and return a partial view that renders that sub-nav. Your AJAX callback will then take this response, select a portion of the DOM (specifically the parent of the sub-nav) and insert the new HTML as its innerHTML.
If you're going to be doing a lot of this, you'll want to make use of some client-side MVC-style JavaScript library, like Angular for example. These make it trivial to wire everything up.
Let's say that I have a blog where each post can have several sections and comments and I'd like to use a hard-links to navigate and operate on this. There are several samples using some pseudo-code, of course they doesn't work, just demonstring my intends :)
Of course /blog.html#/posts/1 uses PostRoute, PostController etc and uses :post_id for finding object - that's obvoius.
How can I pass (and then access) additional params which doesn't change the controller but I can use them to navigation. ie /blog.html#/posts/1?section=123 should use the same route, controller and view as it was just Post, but I'd like to read the section and just navigate to section with #123
/blog.html#/posts/1/?comments=456 - actually should behave like section from point 1, but navigates to comment and optionally add some class to the container.
Other case: I'd like to go to section 123 AND additionally edit it with link like: /blog.html#/posts/1?section=123&action=edit. Now I'm using a button with an action like {{action editSection section}} and {{#if isEdit}} but I'd like to be able to reflect this in URL and also go to this state from URL (de facto my post can have several different modes not only preview/edit, therefore it should be accesible by the link).
I hope that cases makes sense, TBH I have no idea in which direction should I go. Tried with nested routes, but I'd like to avoid changing the controller. Also have no concept how to reflect the action in the URL...
I'm using Ember 1.1.2
You can use the model method of the route to handle such parameters, separate them from the model parameter and set the appropriate controller state.
Another approach would be to use nested routes that will render un-nested views(and controllers) - as explained towards the bottom here.
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
I'm having a really hard time understanding routing.
Please help me with this problem.
Each of my controllers have these three actions right now
Users have Index, Create and Edit
Locations have Index, Create and Edit
Companies have Index, Create and Edit
The thing is, it all gets done through ajax.
I have jquery ui tabs with two tabs for each, Create and Edit
So the Index method is always the one that gets called for action links.
and inside this main view is that you can call(by clicking on the tab icon) the other methods that return an ajax view that gets output into the jQuery tab (I hope that's clear)
I have a sidebar with links to the controllers. and to specific methods of these controllers. The wanted behavior is that it should actually go into the Index Method and then with some logic autoload the wanted tab.
It all works just fine right now. But my urls are horrible.
To get to the create method for Users I have to go this url
http://localhost/Users/Index/1
http://localhost/Users/Index/2
I want the behavior of these links to be remapped to these links
http://localhost/Users/Create
http://localhost/Users/Edit
So even though it seems as if you are calling the Create method of the controller you are actually always calling the Index method.... (I know how to transform Create into "1" and Edit into two, so don't worry about that part
Hope that's clear.
Thanks in advance
Edit:
Just realized that this might not be possible cause then when I actually need to call the methods (with ajax) it wont know what to do.... am I correct?
Without seeing your controller action, you should be able to add a route something like this:
routes.MapRoute("myroute","users/{option}",new {controller="Users",action="Index"});