Rails link_to item with next position in array - ruby-on-rails

I'm trying to create links to navigate through an array. I have three classes:
fsets, line_items, and exemplars.
In my app I have it so on a page a user is shown an image. I want the user to be able to click a next/previous link to go to the next element in the array. I can currently display all the images on the page but can't find out how to create the next/previous links. Elsewhere in the app I have used the following to go to the next record in the db but can't figure out how to implement the same for the array.
def previous
Exemplar.where(["id < ?", id]).last
end
def next
Exemplar.where(["id > ?", id]).first
end
I was hoping that if I could return the index position in the array I could link_to the next one but I can't figure out how to do that. I started by displaying the current position of the element and the previous/next positions.
next: <%= (params[:pos].gsub(/\D/, '').to_i + 1) %>
current: <%= params[:pos].gsub(/\D/, '').to_i %>
previous: <%= (params[:pos].gsub(/\D/, '').to_i - 1) %>
I am passing the index position of each element in the params using the :pos. So when the page first loads the :pos is set to 0. There are links on the bottom of the page allowing the user to jump to items in the array. Those links pass the index position as well. I know there is an easier way to do all this and I've gone down the wrong path/way of thinking about all of this. Just thought it would be helpful to show what I've tried even if completely wrong.

This gem will do what you need. https://github.com/mislav/will_paginate
If you can link to your github i might be able to help more. You will want to extract that pagination logic out to somewhere that is not the activerecord model.

Related

Going Through Users in Database Individually

I have been searching and searching for help on this question, but I have found no luck. I am wanting to have a page that displays each user in my database one at a time, and when I press a 'Next' button, it will go to the next user in the database and display their information. I have been seeing this code everywhere:
<% #users.each do |user| %>
<li>
# Add some code
</li>
<% end %>
but this is displaying every user all at once on my page. I would like to only display a single user at a time. If anyone could direct me to a good source or has a simple explanation, I would be forever grateful!
You just need to paginate the #users records. I prefer using will_paginate gem.
After including it in your gem file, you may use it like:
#users = User.paginate(:page => 1, :per_page => 1)
For basic understanding, the gem basically uses limit and offset in SQL query to attain the record. If you don't want to use the gem, then you may try like:
User.limit(1).offset(params[:offset].present? ? params[:offset] : 0)
And on clicking on next you may pass the incremented value of offset each time as parameter.
have a look at the kaminari gem. You will be able to paginate your results one by one (one result per page, hence the name).

rails 3 displaying a where

using the below code i can search a table using the question id and position where position will be the biggest number
<%= #question = Question.where('question_group_id' =>params[:question_group_id]).order(params[:position]).last>
however i get
#<Question:0x3fe85c0>
how do i display it with the actual position number
thank you
I know it may be a repost but i found two or three answers on these boards pertaining to different questions where the user got a similar result but they didnt help
Do this part in your controller:
#question = Question.where('question_group_id' => params[:question_group_id]).order(params[:position]).last
And you can use this part in your view to show all the attributes
<%= #question.inspect %>
Or to show one attribute you can use
<%= #question.position %>
Note that when you put it in the <%= %> tag it automatically will perform a to_s, so while you might see something more verbose printed in your console when you check what #question is, to get what will actually display, try #question.to_s
(also note that #question will not be available in the console, but you can copy and paste the relevant code)
Question.
where('question_group_id' => params[:question_group_id]).
order(params[:position]).
last
returns an instance of Question. That being said if you want the position you must get the attribute. So all you need is to call .position after .last

Rails - Submit multiple forms on same page

Model:
Users have expenses. Expense has a status.
View:
As users add their expenses, they are shown in a list. Each expense row has a form button on the end, which is used to submit the expense (changing the status of the expense). This allows users to add expenses they have not completely filled out, and submit them when they are ready. There is no parent form on this page, just the form buttons which submit the expense to a method which changes the status, and then reloads the page.
Currently it works great, but users have asked to be able to "submit all" the expenses that are showing on the view with a single button.
Question:
What is the proper way to handle this in rails? Should I find a way to gather the array of expense id's and then submit a separate form? Is there a way to ask for a set of records present in a view with a certain status?
Thanks!
Another option, if I'm thinking about this right (big if), would be to wrap your page in a User form. Then you could have something like...
<%= form_for(#user) do |f| %>
<% #user.expenses.each do |expense| %>
<% f.fields_for expense do |e| %>
<!-- expense form -->
<% end %>
<% end >
<% end %>
This is something you could submit as a whole. I'm having trouble picturing what a single expense addition might look like, but hopefully this gets you a little further down the road.
Edit: in addition to having this User form on the page, you could have an "extra" Expense form to create an expense. When you submit a new expense, that expense appears in the list under the user form, where it can be edited or submitted, either as part of a group or individually (as part of a "group" of 1).
custom controller action:
def update_all_expense_statuses
expenses = current_user.expenses
ExpenseUpdater.new(expenses).update_expense
redirect_to :back
end
expense updater class:
class ExpenseUpdater
def initialize(expenses)
#expenses = expenses
end
def update_expense
#expenses.each do |expense|
expense.update_attributes(status: 'paid')
expense.save
end
end
end
This is just an example of one way to update all the user's expenses with a custom controller action. Just call the controller method from a link_to:
<%= link_to "Update all expenses", update_all_expense_statuses_path %>
Remember to add it to your routes. Hope this helps.
The first thing you should do is change the forms to submit remotely, ie make an ajax request. Then you're not reloading the whole page. Check out Rails' various "remote" form helpers, eg "remote_form_for".
Then, write a javascript function to submit all the forms for inputs that have changed since the page loaded. You'd probably want to add a "changed" (or similar) class to the parent form in an onchange event in each input, to facilitate this. I think this is the best way to handle the "status" thing you're asking about. Make a "Submit all" button which calls this function.
Use a form/service object http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/ to encapsulate expense report

How to render horizontal page layout with multiple frames

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.

Ruby on Rails: Adding a user for login to my existing app killed my index

I have an app that I've been developing that has so far only been a single user environment. I finally got to the point where I needed to add multi-user capabilities so I followed the railscast on authlogic to get a simple login.
I then added a has_many :items and accepts_nested_attributes_for :items and a belongs_to :user to the correct models. I then dropped the database and setup and then migrated it. I also added a user_id column to all my nested models.
After that, when I click on the "Create new item" link, I go to the new page and create a new item. When I go back to the item_index page, it's not showing up anymore. I can go to localhost/item/1 and see the record, so I know that it's being created, but when I try to view it in my item_index.html.erb it doesn't show up anymore.
Here's the basic loop that was working before I added the user. (It's rendering into a table)
<% for item in #items %>
<%= link_to item.name, item %>
<% end %>
I imagine that the loop is what's wrong, but I'm not entirely sure.
Thanks
edit: Here's what's happening in my index method in my item controller:
def index
#items = Item.search params[:search]
if #items.nil?
#items = Item.all
end
end
I have the weird if nil? thing because I'm using thinking-sphinx and it was failing sometimes if the index was empty.
edit2:
If I change the index to have just
def index
#items = Item.all
end
Everything shows up. So that means that it has to do with thinking sphinx messing with my render
edit3: in thinking-sphinx fashion, I did some things unrelated to it, and it magically works again.
Thinking Sphinx is going to be returning an empty result set [], when you try to iterate over this empty set you're not going to get any items shown.
To my knowledge, Thinking Sphinx will never return nil for a search result.
Perhaps try this instead:
if #items.empty?
#items = Item.all
end

Resources