How to display all instances of a model in Rails? - ruby-on-rails

In my web application the user can select certain instances of an entity. For instance on the class BubbleGum, now the user can select certain instances of BubbleGum by adressing their identifier:
gums/details?show=3532667
Now, in addition I also want to make it possible to display all BubbleGums. For this I have introduced the convention of using * to identify all
gums/details?show=*
This works nice so far, but often I have to add a bit code to process the * selection. Is there a nice way to represent an all-instances object in Ruby and/or Rails?
I have thought of using simply a dedicated symbol, constants, or an actual object of the class BubbleGum that represents all the other bubble gums.

To display all the entities in a rails application generally we use a index page.
bubble_gums_controller.rb
def index
#bubble_gums = BubbleGum.all
end
views/bubble_gums/index.html.erb
<% #bubble_gums.each do |bubble_gum| %>
<tr>
<td><%= bubble_gum.name %></td>
<td><%= bubble_gum.price %></td>
</tr>
<% end %>
Refer this for further details.
http://guides.rubyonrails.org/getting_started.html#listing-all-posts

I think you want to use the query string param show.
So, you can try in your gums controller:
def details
if params[:show] == "*"
#bubble_gums = BubbleGum.all
# ...
elsif params[:show]
#bubble_gum = BubbleGum.find(params[:show])
# ...
else
render :status => 404
end
end

Related

How to avoid hitting database in the view

I get that one should not ping the database in the view... but wondering about the right solution. In one of my views, I need to pull info on an #order, it's child items, and also Amount, another model, based on each child item. Something like this:
<% #order.items.each do |item| %>
<td><%= item.name %></td>
<td><%= Refund.where(item_id:item.id).first.amount %></td>
<td><%= Amount.where(item_id: item.id).first.amount %></td>
<% end %>
For the sake of avoiding the db hits in the view, the only solution I've thought of is to create a huge hash of all the relevant data in the controller, which is then accessed from the view. So it would be something like this:
# controller (writing quickly, code may not be totally right, hopefully you get gist
data = Hash.new
data["items"] = []
#order.items.each do |item|
item_hash = {
"name" => item.name,
"amount" => Amount.where(item_id: item.id).first.amount,
"refund" => Refund.where(item_id:item.id).first.amount
}
data["items"] << item_hash
end
# view code
<% data["items"].each do |item| %>
<td><%= item["name"] %></td>
<td><%= item["refund"] %></td>
<td><%= item["amount"] %></td>
<% end %>
And I know SO hates this type of question... but I really need to know... is that the best solution? Or are there are best practices? The reason I ask is because it seems very clean in the view, but very bulky in the controller, and also it gets quite unwieldy when you have a much more complex set of nested tables, which is what I actually have (i.e., the data hash would be quite funky to put together)
First of I would use associations between item and the 2 other classes, so that you can do
item.refund
item.amount
Instead of Refund.where(...). You could further define methods such as
def refund_amount
refund.amount
end
And similarly for the other one (and hopefully come up with a better name than amount_amount.
This keeps both your view and controller clean but it won't be any faster. So far all of the approaches involve running 2 database queries per item which is the real issue as far as I'm concerned - whether those excess queries happen in the view or the controller is of lesser concern.
However you can avoid this with Active Record's include mechanism:
Item.include(:amount,:refund).where("your conditions here")
Will load the named associations in bulk rather than loaded them one at a time as each item is accessed.

Ruby On Rails Display Image

I am a newbie at it.I have just educated myself for 2 days. And a have a problem.
Example: I have a table , called as tblData, includes 2 columns: id, img_link. img_link contains link to an image.
I want to show all of them in this table(id and image, not image link) into a html file.
So, exactly what I need do?
If you have an image link that you can pull from your database, you can do something like this:
Assuming you have an object assigned and everything's set up:
In your controller for tbl_data (e.g. app/controllers/tbl_data_controller.rb):
class TblDataController < ApplicationController
def your_action
#tbl_data_item = TblData.first
end
end
(The code above is just an example, you should substitute for whatever code/query you wish to run)
In your view template, you can render an image from a link using the following Rails view helper:
<%= image_tag(#tbl_data_item.img_link) %>
This would output the following HTML:
<img src="/path/to/image/from/img_link" />
There's a lot more info on this helper on the Rails api docs. The Rails Guides has some awesome info on getting things set up and running as well. Hope this helped!
UPDATE:
To give you a better example with clearer steps, you would do something like the following:
Set up your routes (app/config/routes.rb):
Rails.application.routes.draw do
resources :tbl_data
end
Create your model, used to communicate with its respective database table (app/models/tbl_data.rb):
class TblData < ActiveRecord::Base
# your model-specific code goes here - validations, scopes, etc.
end
Create the controller, which responds to when a user hits a certain route in your app (app/controllers/tbl_data_controller.rb):
class TblDataController < ApplicationController
def your_action
#tbl_data_items = TblData.all
end
end
Create the view template, that will be rendered for your user(app/views/tbl_data/your_action.rb):
<table>
<% #tbl_data_items.each do |item| %>
<tr>
<td><%= item.id %></td>
<td><%= image_tag(item.img_link) %></td>
</tr>
<% end %>
</table>
The above would show a table with each record in the #tbl_data_items as a row, with 2 columns, one with the id, and one with the actual image for that item.
Create a folder in public called images, put the desired image in that folder.
Put <%=image_tag 'whatevertheimagefilenameis.png', class: 'example-class', id: 'example-id'%> in the html.

undefined method `order' for "1":String

On my landing_pages "show" page, I'm trying to show the leads that came in via that page and sort them via their "score".
My landing_page model has:
has_many :page_leads
My page_lead model has:
belongs_to :landing_page
In my index method within my page_leads controller, I have this, which works:
def index
#page_leads = PageLead.order(score: :desc)
end
I try to duplicate this in the landing_pages controller for the show method. Here is what I have:
def show
#landingpage = LandingPage.find(params[:id]).order(score: :desc)
end
When I try to go to the "Show" page, I get an error "undefined method `order' for "1":String". How can I get this to work?
My show page has the following code:
<tbody>
<% #landingpage.page_leads.each do |page_lead| %>
<tr>
<td><%= page_lead.fname %></td>
<td><%= page_lead.lname %></td>
<td><%= page_lead.score %></td>
</tr>
<% end %>
</tbody>
It is just:
def show
#landingpage = LandingPage.find(params[:id])
end
Cause find returns the LandingPage with id == params[:id]. No need to sort a single item.
find returns an array or records if the params[:id] is an array.. the order can't be applied to the array, because order isn't part of the array class.
If params[:id] is a single element then the find returns the record. Again order doesn't apply, because it's just one record not a container of records..
If you want an sorted list then use
LandingPage.where(id: params[:id]).order
But since this is in the show I suspect you want the single item... As spickermann said drop the order
LandingPage.find(params[:id])
If you want to sort Page Leads, you would do something like
def show
#landingpage = LandingPage.find(params[:id])
#page_leads = #landingpage.page_leads.order(score: :desc)
end
As #spickermann mentioned, .find() only returns one model instance. You can't order this using ActiveRecord query methods.
If you want to order the page leads, you have to call .order on the set of page_leads that belong to the landing page

Rails Scope, Helper Method?

I have three models. One is an Employee, one is an Item, and one is a Transaction that belongs to both Employee and Items. It's a simple app that allows Employees to check in and check out items - 'Transaction' has a boolean column for checked-in/checked-out.
What I'm trying to do is show within the employee/show view the current list of Items that an Employee has checked out. This is some rough code that I sketched out, but I'm not sure that it's going to work, and I was told not to use a lot of nested conditionals in my views anyway.
<% if #employee.transactions.exists? %>
<h3>Currently Checked-OUT Items</h3>
<table>
<tr>
<th>Item Asset Tag</th>
<th>Item Description</th>
</tr>
<% #employee.transactions.each do |transaction| %>
<% if item.transaction.last? && transaction.status == false %>
<tr>
<td><% transaction.assettag %></td>
<td><% transaction.description %></td>
</tr>
<% else %>
NO CHECKED OUT ITEMS
<% end %>
</table>
<% end %>
<% end %>
Basically, I'm trying to:
checks all employee transactions
compares the item involved in the transaction and sees if it's the .last transaction record for item
if it is, and if it's false, then it's a current checkout.
Is this a better job for a scope within the Transaction model, or a helper method? I've never used either, I'm really new at rails.
You should do a couple of things in here.
First - create a scope that will fetch last item transaction for you. There's no point in going through al item transactions if you're interested in the last one only, right?
Second, use partials. In this example it's hard to show how I would refactor code to use them (some things doesn't make sense here, ex. where does item variable come from?)
Scope example (take last transaction)
#item.transactions.order('created_at DESC').first
You can as well add scopes for checkin / checkout
class Transaction
scope :checkin, -> { where(status: true) }
scope :checkout, -> { where(status: false) }
end
First, you are on the right track. When views get ugly and hard to read because of extensive embedded ruby conditionals and such, think about moving the logic into a helper.
If you have a typical rails app, you'll already have app/helpers/application_helper.rb
So you could just create a helper in that file
def make_employee_list(employee)
if employee.transactions.exists?
content_tag(:div) do
content_tag(:h3, "Currently Checked-OUT Items")
content_tag(:table) do
employee.transactions.each do |transaction|
# you get the idea
end
end
end
end
end
Then in your view you could do this:
<%= make_employee_list(#employee) %>

Create a class to populate page in ruby 1.8.7

I'm trying to make a class to populate a deals tab on my website.
Part 1. Take an items close date (CatalogItem.close_date) and use all items within 12 hours of closing. Part 2. Calculate the deal percentage by using the current price (CatalogItem.current_price) and estimated value (Item.estimated_price) <-- You'll notice they're in different tables but they're identified by an identical item_id.
I'm green in RoR, so I'm having trouble connecting this in a class, but I can make it work individually in the console:
hour_diff = (CatalogItem.last.close_date - Time.now) / 1.hour
deal_percentage = (CatalogItem.last.current_price.to_f / Item.last.estimated_price)*100
As you can see I'm using my .last piece of data, but I want to create an array that runs through all my items, that's where my knowledge goes dry, any help would be much apreciated
I'm assuming you are using a belongs_to, but I think what you want to do is use
an instance method. This would be your model, app/models/catalog_item.rb
class CatalogItem < ActiveRecord::Base
belongs_to :item
def hours_remaining
(close_date - Time.now) / 1.hour
end
def deal_percentage
(current_price.to_f / item.estimated_price)*100
end
end
Then, you could access them in a view something like this:
<table>
<% CatalogItem.all.each do |ci| %>
<tr>
<td><%= ci.hours_remaining %></td>
<td><%= ci.deal_percentage %></td>
</tr>
<% end %>
</table>

Resources