Ruby on Rails 3. I have a page with several div blocks. I am trying to seperate them into two pages. I want a button at the bottom of the page which will change the rendered partial.
The "render 'news'" is the first partial loaded. I want the "Archived News Postings" button to change the 'news' to 'archive_news'
<%= render 'news' %>
<%= link_to render(:partial => 'archive_news'), :class => 'btn' %> <button type="button" class="archive">Archived News Postings</button>
Can I get a pointer? Thank you
It depends on what you want to achieve really. For instance, these two options could be considered:
1) You could fetch both the news items and the archived ones. Then render two divs with the corresponding news items. The one with news is shown while the other has display: none; in the CSS. This allows you to use JavaScript to toggle the divs visibility. This obviously has some disadvantages with amount of data etc. but it gives an idea what to think about.
Something along these lines:
controller:
def some_action
#items = ...
#archived_items = ...
end
view:
<div id="news">
<% #items.each do |i|
...
</div>
<div id="archived_news">
<% #archived_items.each do |i|
...
</div>
css:
#archived_news {
display: none;
}
2) Another way would be to rely on asynchronously fetching the news items as the used wants to "toggle". This can be done with AJAX. This allows for more flexibility if the data set is large. You can even have "fetch more" in some way that archived news items are loaded on demand if needed.
If you shed some light what you might need it is possible to give a more specific answer.
Related
I've only ever used a static default scope for my projects and my latest one I wanted to create a dynamic scope feature, where the user can click a button or use a dropdown menu to change the order they view a list.
so far I've come across a few methods like using unscoping and setting a new scope, and seen reorder. I'm looking at the docs but I also am unsure of how to make a user be able to choose. Would I use something like Link_to, or button_to in the corresponding HTML.erb file?
in my post.rb file it'd look like this
default_scope { order(created_at: :desc) }
scope :ordered_by_title, -> { reorder(title: :asc) }
scope :ordered_by_reverse_created_at, -> { reorder(created_at: :ASC)}
I added those other scopes under the default because I assumed one would set the scopes they wanted and the view would call/activate them once a user clicks or chooses it from the rendered page.
in my post_controller.rb
def index
#posts = Post.all
end
in my index.html.erb the view
I have the list of posts rendered this way, if it won't work with what I want to do can someone show me a better way to do it?
# <some way for user to choose those defined scopes and render the new page would go here>
<% #posts.each do |post| %>
<div class="media">
<div class="media-body">
<h4 class="media-heading">
<%= link_to post.title, post %>
<small> <%= post.body %> </small>
</h4>
</div>
</div>
<% end %>
There are basically two ways to do this:
purely front end, use js. You can use some existing js plugin with sorting abilities if you don't feel like writing your own (e.g. DataTables). You'll probably need to make a table with the different attributes available for this to work.
back end, use ajax. Write your own or use something like filterrific, which uses scopes for filtering and sorting.
I'm working on an forum-type app in Rails v 4.2.5. My index page is a list of all the questions being discussed in the application and they are default sorted by the created_at date. I am also using the Kaminari gem to paginate all of the questions (25 per page). I originally had my app set up like this:
Questions Controller:
def index
#questions = Question.order(:created_at).page params[:page]
end
Index View:
# I render a partial that iterates through the questions list to display
# the title of the questions, then I include the paginate code below.
<div class="pagination">
<%= paginate #questions %>
</div>
I eventually decided I wanted users to be able to sort the questions by different criteria (e.g., by total amount of upvotes, by total amount of responses for a question, and by recently asked questions). Right now, you can click a link corresponding to the type of sort you want and it will AJAX the new sorted list (a partial) onto the page. However, when I do this, the pagination does not work and when I click to see the second page of the results, everything becomes unsorted.
Index View with Sort Links:
<div class="sort_selection">
<h3> Sort By: </h3>
<%= link_to "By Upvotes", "/questions/top?sort=votes", class: "question_sort_link" %>
<%= link_to "Answers Provided", "/questions/top?sort=answers", class: "question_sort_link" %>
<%= link_to "Recently Asked", "/questions/top?sort=recent", class: "question_sort_link" %>
</div>
Index Controller:
def top
case params[:sort]
when "votes"
#questions = Question.sort_by_votes #sort_by_votes is a method in my Question model that performs a SQL query
when "answers"
#questions = Question.where.not(answers_count: nil).order(answers_count: :desc).limit(25)
when "recent"
#questions = Question.order(created_at: :desc).limit(25)
end
render partial: 'questions_list', layout: false
end
Javascript AJAX
$(document).on("click", ".question_sort_link", function(event){
event.preventDefault();
$.ajax({
method: "get",
url: $(this).attr("href")
}).done(function(sorted){
$('.questions_show_sorted').replaceWith(sorted);
});
});
I fooled around with the placement of the <%= paginate #questions %> in the view, as well as removed the 25 limit in my controller and added .page params[:page] after all of the queries in the Top route but I still cannot get the pagination to work after I've AJAX'ed a sorted list onto the page. Does anyone have any suggestions?
When you are switching pages the data about sorting is lost, because you are reloading site with different parameters. You can either try to pass this data (the column you are going to sort, and info is it asc or desc) to the new page, and sort it before loading, or paginate it using AJAX (but that means loading everything at the first load). I can't tell about the "pagination does not work problem", because I don't know what you mean.
In general, this thing you are trying to do is rather complicated, and there is no simple solution for that. There is a library for JS called Datatables that (in theory) makes it easier. There is another library called jQ-Bootgrid, and a ruby gem called "Smart listing".
I think you need to provide the pagination links in your ajax response and replace them in your javascript callback.
I assume that you return html rather than json, which will make this a bit awkward. Perhaps you could build up a json response with pagination links and html content
{
next: /list?page=3,
prev: /list?page=1,
content: "<ul>
<li>foo</li>
<li>bar</li>
</ul>"
}
We have a simple app which has a horizontal layout (left hand side panel and content on the right hand side), with a header and footer. So if you click on a certain object on the left hand side, the view is rendered on the right hand side with navigation panel in the header and footer links. The layout actually renders content on the same page itself for any action on the left hand side and the contents of the left hand side will differ based on the section chosen in the header. How should we go about designing the routes in these cases, which differs from the basic navigation where every action is rendered on a different page.
My routes looks like this..
resources :foos do
resources :foo_bars do
end
end
I would need to show all foos on the left hand side panel and if the user selects a foo it needs to show properties of foo and foo_bars in a table on the right hand side panel. How will the view look for me and how will the URL at the browser look for me? We will have several tabs at the top and based on that you will show foos or similar top level objects
The routes remain the same. You would need to ajaxify your calls.
If your question is:
how should we go about designing routes
The way you have it is just fine if you want to utilize nested resources, and in your case it seems logical.
http://guides.rubyonrails.org/routing.html#nested-resources
Currently, your url will be as follows: /foos/:foos_id/foo_bars/some_action
Let me rename these so things make more sense. Lets say foos is categories, and foo_bars is actions.
Personally, I would override the to_param in the categories model file.
to_param
#return a more readable attribute here
name
end
In this way, your URL would be more closely tied with the names of all the categories on the left side of your page.
So now, if you had a record in the categories table which had the name animal, your URL would look like this: /categories/animal/actions/some_action
That seems pretty logical to me. Make sure in your controller you fetch the record via the proper attribute if you use to_param.
I would apply the same principal to the nested resource as well, then your whole URL would be accurately representing what tab is selected on the page. If you had a record in actions with the name "running", and you had things setup properly, then you could have your url look similar to: categories/animal/actions/running.
You could play around with all the options in your routes file, then use rake routes in terminal to see what changes and what your urls will look like before you even touch the browser.
Here are some extra resources for you.
http://apidock.com/rails/ActiveRecord/Integration/to_param
http://guides.rubyonrails.org/action_controller_overview.html
Hope this helps.
There is no good answer to your question - it all significantly depends on the layout of your application. Besides, there are valid answers here about to_param, and using AJAX, that add important details. But, to give you a head start.
For your views/foos, rewrite your index.html.erb as:
<%= render partial: "show_foos", locals: { foos: #foos, selected_foo: nil }%>
And your show.html.erb as:
<%= render partial: "show_foos", locals: { foos: #foos, selected_foo: #foo }%>
In your foos_controller.rb in show method you need to obtain both #foos and #foo, e.g.:
#foos = Foo.all
#foo = Foo.find(params[:id])
Now, to the fun part. Back to views/foos directory. Create a partial called "_show_foos.erb" (the one that we called both from #index and #show). Do something like:
<table>
<tr>
<td>
<%= render partial: "show_foos_list", locals: { foos: foos, selected_foo: selected_foo }%>
</td>
<td>
<%= render partial: "show_foo_props", locals: { selected_foo: selected_foo }%>
</td>
</tr>
</table>
Please note that's an extremely brute & ugly example that creates a table with two columns: one for the list of foos in the left "panel", the other for displaying the results for the selected foos in the right "panel". In real life use divs and styling. Also, consider pushing the layout to where it belongs - to the appropriate layout file - and using named yields there. But, as I said, a headstart - simple table.
Now, just define the two partials mentioned here. First, the "_show_foos_list.erb" that lists the foos on the left. Assuming each foo has a 'title' attribute, something like:
<% foos.each do |foo| %>
<%= link_to_unless selected_foo && (foo.id == selected_foo.id), foo.title, foo %><br />
<% end %>
Second, the foo & foo_bars on the right - "_show_foo_props.erb":
<% if selected_foo %>
# Here display the Foo attributes
<h2> Foo: <%= selected_foo.title %> </h2>
<% selected_foo.foo_bars.each do |foo_bar| %>
# Here display each FooBar that belongs to Foo
<h3>FooBar <%= foo_bar.title %></h3>
<%= foo_bar.description %>
<% end %>
<% end %>
Again, very crude example. Replace 'title', 'description' with the right sets of parameters, use partials to display FooBars. Do the styling with CSS. Etc, etc, ... Refactor as you see fit.
Talking about the routes. What you get is when you go to your "www.yourapp.com/foos" url is the list of all foos on the left, nothing on the right. Once you press on any foo in the left column, you go to "www.yourapp.com/foos/:id", where :id is the ID of the selected foo (and consider to_param from the other answer here or more advanced techniques to make this part meaningful) and get the list of foos on the left, and the properties of the selected foo and all foo_bars belonging to it on the right.
Hope that helps to start laying out your own implementation based on the rough idea presented here.
If I understand your question correctly, the answers saying Ajax is required are not correct. I have an ancient Perl app (written in 1999) that does this. Am currently re-implementing in Rails, and it's working fine. Frames make it particularly easy to allow the data to scroll while the menu stays fixed.
You do need to use HTML4 frames, which are deprecated in HTML5, It's possible to use an IFRAME for the data rendering frame and be HTML5 compliant, but the result is less usable than the FRAME solution in HTML4, at least with some browsers.
As others have said, your routes are fine.
The trick is to use the target field in the form to direct the Submit response to the rendering frame. My haml code for the "command" frame is
= form_tag admin_menu_path, :method => :put, :target => 'data_frame' do
...
The rest is just a normal form. This form remains constant in (my case) the left frame while responses replace each other in the right data_frame.
The matching frame HTML is:
<frameset cols="360,*">
<frame name="menu_frame" src="...">
<frame name="data_frame" src="admin.htm">
</frameset>
You would have to use an outer frameset to get the header and footer, but this should be straightforward.
I am ready for comments saying frames are far from best practice. But for this particular application, they are perfect: simple, understandable, and extremely browser independent. E.g. my 1999 Perl generated code ran fine on IE 2.0 and Netscape (the ancestor of Firefox, friends). And it's still perfect on every modern browser I can find. Wish Ajax could say the same...
If I've misunderstood your question, I'll happily delete this response.
I would like to have a right side bar with content changes for each page.
For example, when I am in Friends page, the side bar should display New Friends.
When I am in Account page, the side bar should display Recent Activities.
How should I go about this to respect Rails design patterns? I heard about Cells gem, but I am not sure if I use it.
here is one way, in your layout add a named yield section
<div id="main-content">
<%= yield %>
</div>
<div id="side-content">
<%= yield(:side_bar) %>
</div>
Then in your views put content into the named yield using content_for
# friends view ....
<% content_for(:side_bar) do %>
<%= render :partial => "shared/new_friends" %>
<% end %>
# account view ....
<% content_for(:side_bar) do %>
<%= render :partial => "shared/recent_activity" %>
<% end %>
this requires you to be explicit about what content appears in the side bar for every view,
maybe having it do it dynamically is better? probably depends on the specific situation and your preference
see also - http://guides.rubyonrails.org/layouts_and_rendering.html#understanding-yield
I came by this question in a moment of a big design change in our views. After thinking about the sidebar problem a bit, I realized that there's no best solution (as always). There are better solutions for each case.
I'll compare 3 solutions here:
using content_for(:sidebar) and yield(:sidebar)
using the partials approach
using the Cells gem
1. Using content_for(:sidebar) and yield(:sidebar)
This is good for cases when each link (each controller action) you access renders a different sidebar. In this case, each view you access will have the content_for(:sidebar) part.
If your sidebar view depends only on the state of some variable in the session, for example, the sidebar should not be rendered for every link you access.
Then you should use a good caching system like turbolinks, to avoid rendering many times the same thing, or use something like the Cells gem with a javascript to render only the main part of the layout.
2. Using partials
Using partials is always good to eliminate duplication. If your sidebar is very simple and is changed for every controller, you can render it as a partial. But if you're rendering different partials in the same controller, according to some state, it may be an indication that you have business logic in your views, which should be avoided.
3. Using the Cells gem
Very good design pattern when you have to render your sidebar from a different controller than the rest of the view each time.
It takes a lot of business logic out of the view, which sure is a good practice.
Here you have an action calling a view. Inside that view, there is a statement render_cell(:sidebar, params). This statement will do some business logic and render the view of the sidebar. It's as if the first action called other controller actions to render specific parts of your view (called cells)
If you make changes to the sidebar only, you may have to create other simple action, so that a javascript will request it. This action will call the render_cell(:sidebar) method again to respond with the view.
It's a very interesting approach.
Other ideas:
Your sidebar could be rendered only with javascript from the same
action.
Your sidebar could be rendered by an angular controller, and rails sends jsons with the sidebar objects. (look for "One page apps")
try something like this
<div class="sidebar">
<% if current_page?(controller => "friends", :action => "show") %>
<h4>New Friends</h4>
<% elseif current_page?(controller => "accounts", :action => "show") %>
<h4>Recent Activities</h4>
<% end %>
</div>
If the above code fits what you are trying to do(looks like this is what you want to achieve), then stick with it, else it may be beneficial to go with some gems. Also checkout helper page on how to use current_page? method. Hope it helps
I am using Rails 3. Consider the following code listed at bottom.
1) Should links to other actions be done via href (href="/foo/bar") or via #id (id="#foobar_div")? In some document I read online. Providing an actual link to the href attribute tells the iPhone to execute an AJAX call.
If I provide an div#id instead, then it loads the page without ajax (the same way browsers do this). However, providing div#id's means that all content has to be declared a single page.
Whats the right way for calling other pages on the server?
2) Is there anything wrong with the code structure below? i.e. can I style my own span elements like this?
3) The demo pages indicate that all content should be in one page. However, Ryan Bates from railscast.com has an episode about jqtouch and his pages are separate. which is the proper way?
<ul>
<% #songs.each do |song| %>
<li class="arrow">
<%= link_to(song_path(song)) do %>
<%= image_tag(song.user.profile_image, :alt => 'profile image', :style => 'float:left;') %>
<span class="title"><%= song.title %></span>
<span class="artist">by <%= song.user.first_name %></span>
<span class="likes"><%= song.likes.count %> loves</span>
<% end %>
</li>
<% end %>
</ul>
For your first and third questions (which to me are the asking the same thing), it depends on the project you're working on.
If you're providing static contents, you can just load all the pages in one hit, hence using "id=#foobar_div", as long as there are not that many pages (as you don't want the users to hold the phone and look stupid in front of their friends waiting 30 minutes for your site to load).
If you're providing dynamic contents or there are too many pages for your site, you may want to use the AJAX approach, at least for some pages.
At the bottom line, you want to load as many static pages as possible while still keeping your site responsive.
For question 2, I'm not quite sure I got what you're asking. I can't see anything obviously wrong, but again, I'm not a rail programmer.