How to get name of foreign key - ruby-on-rails

In my Rails app I have a list view of device ports and each device port belongs to a device:
device.rb
has_many :device_ports, :foreign_key => "device_id"
device_port.rb
belongs_to :device
device_port_controller.rb
def list
#device_ports = DevicePort.paginate(:all, :page => params[:page], :per_page => 100, :order => "name")
#devices = Device.find(:all)
end
list.rhtml
<table width="100%">
<tr>
<th>Name</th>
<th>Device</th>
</tr>
<%= render :partial => 'device_port/list_item', :collection => #device_ports %>
</table>
_list_item.rhtml
<tr>
<td><a href='/device_port/update/<%= list_item.id %>'><%= list_item.name %></a></td>
<td><%= list_item.device_id %></td>
</tr>
So I am displaying the device_id from the device_ports table but I actually want to display the name column of the devices table instead.
I have done something very similar and probably slightly more difficult elsewhere in my app where I have a preselected dropdown with the correct device name selected but I can't seem to figure out how to do it outwith the context of a select menu.
I have the devices in the #devices variable in the controller above and was trying to look that up using the list_item.device_id but it didn't seem to work.
It's probably quite a straightforward thing but I just can't seem to find the proper way of getting the desired result.

as device_ports belongs_to device so list_item.device.name Thanks!

I just tested this out in the console but it should work. You can call columns on your model which returns an array.
So, what I just used my User model:
User.columns[0].name #=> 'id'
Presumably yours will be
Device.columns[x].name
EDIT: I read the the question as "name [of the] column"

Related

Render of object missing the specified nested include

I am migrating a Rails app from 3.2 to 5.1, and it includes a simple enough model which includes a reference to the product type of the batch,
create_table "batches", :force => true do |t|
t.string "code"
t.integer "product_id"
t.boolean "recalled", :default => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
where, (edited down for clarity)
class Batch < ApplicationRecord
validates_presence_of :product
belongs_to :product
end
I am using will_paginate, so I have the following extract in my model to return a table of records,
def self.search(search, page)
if search
Batch.not_recalled.
where('batches.code LIKE ? OR products.code LIKE ? OR products.name LIKE ?',
"%#{search}%", "%#{search}%", "%#{search}%").
references(:product).
includes(:product).
order(:code).
page(page).per_page(30)
else
Batch.not_recalled.
includes(:product).
order(:code).
page(page).per_page(30)
end
end
And correspondingly, in my controller, I have,
# GET /batches/paginated
def paginated
#batches = Batch.search(params[:search], params[:page])
respond_to do |format|
format.html # paginated.html.erb
format.json { render json: #batches.to_json(include: [:product]) } # note the explicit 'include'
end
end
And in the partial to render the object, I have
<%= product = batch[:product] %> # Try and extract the nested record
<%= puts 'debug' %>
<%= puts batch.inspect %>
<%= puts product.inspect %>
<%= puts 'end debug' %>
<tr role="row" %> >
<td ><%= batch[:code] %></td>
<td><%= product ? product[:duplicate_batch] : 'N/A' %></td>
<td><%= product ? product[:code] : 'N/A' %></td>
<td><%= product ? product[:name] : 'N/A' %></td>
<td><%= link_to 'Show', batch %></td>
</tr>
Now, product is always nil, and the inspect shows the product nested record is NOT included.
I can also examine the JSON, and I can see the included 'product' entry ONLY if I explicitly include it in the format.json line of the controller, as shown above. As there isn't an equivalent syntax to specify the include during the format for the HTML render, I'm not able to render the nested product in HTML.
The really curious thing is I have another very similar model in the same app where this works just fine for HTML too, without an explicit include.
I am aware that ActiveRecord does not load until the last minute, but I am using includes with will_paginate, and I don't see why that would be an issue here. The inspect shows the record, not a ActiveRecord query (I believe).
Two questions:
Why is the nested include not included automatically?
If there's a
good reason for that, how do I specify it to include the product in
the HTML render?
Thanks.
add into model
scope :search, -> (search_param, page) do
includes(:product).
order(:code).
paginate_page(page)
end
Add there also search find part and u should be good
Also i would use activeModelSerializer for serializing objects or
https://github.com/Netflix/fast_jsonapi
Also go rails console
Batch.search(code, 1).to_json(include: [:product]) see whats gets displayed

rails activerecord multiple query

Thanks for your time !
It's a simple question but I've searched for some time and still cannot get the function suit me.
I get a table named *lr_transaction_tables* in DB and a class LrTransactionsTable < ActiveRecord::Base with it.
I can #entry_ary = LrTransactionsTable.find(:all) to fetch the whole table and present it in the view by :
<table id="trans-war-table">
<% #entry_ary.each do |item| %>
<tr>
<td><%= item.ltname %></td>
<td><%= item.name %></td>
</tr>
<% end %>
</table>
But how do I get the data where the data under ltname column is "specific word" instead of all of it.
I've tried #entry_ary = LrTransactionsTable.find_by_ltname( "specific word" ), but it give me the error that undefined methodeach' for nil:NilClass`
ltname and name is the column name in the table.
For Rails 2
LrTransactionsTable.find(:all, :conditions => {:ltname => "specific word"})
For Rails 3
#entry_ary = LrTransactionsTable.where(ltname: "specific word")
OR
#entry_ary = LrTransactionsTable.where(["ltname =? ", "specific word"])
I'll use the where method to set a condition:
LrTransactionsTable.where(:ltname => "specific word")
try best way, always right query in model
in your controller
LrTransactionsTable.find_ltname("specific word")
and write in your model
def find_ltname(name)
where("ltname = ?", name)
end
or you can also create a scope for that
scope :find_ltname, lambda{|name|{ :conditions => ["ltname = ?", name]}
try this:
#entry_ary = LrTransactionsTable.where(ltname: "specific word")

Can't sort table in rails

I'm having trouble sorting a single-column table in Rails. Each row represents a single object (an article) and contains all of its attributes (name, content, created_at, user, etc.). The search function works fine (Article.where) but I can't seem to sort the table by any attributes, i.e. Article.order('attribute'). The default, which I can't change, is created_at desc. Am I overlooking something?
Here is my controller:
def index
#title="Home"
if params[:search]
#search=params[:search]
#articles=Article.where('name LIKE ? OR category LIKE ?', "%#{params[:search]}%", "%#{params[:search]}%").paginate(:per_page => 15, :page => params[:page])
else
#articles=Article.order('name').paginate(:per_page => 15, :page => params[:page])
end
end
And view:
<table>
<%= render #articles%>
</table>
<%= will_paginate #articles, :previous_label => "Prev", :next_label => "Next" %>
Use reorder to override any default ordering.
Article.reorder('name').paginate(:per_page => 15, :page => params[:page])
I recommend my gem simple-search for these problems. It may be too simple, but worth a shot.

Retrieve complex parameter from view Rails 3.1

I'm creating a Rails 3.1 app and I've the following big issue: I must retrieve some parameter from view to controller
This is my view:
<tr class="<%= cycle("odd", "even") %>">
<td><%= text_field_tag("bulk_warehouse_serial#{#count}_page#{params[:page]}", bulk_warehouse.serial, :disabled => true) %></td>
<td><%= text_field_tag("bulk_warehouse_asset#{#count}_page#{params[:page]}", bulk_warehouse.asset, :disabled => true)%></td>
<td><%= check_box_tag "enable_record#{#count}_page#{params[:page]}",1,false,{:onclick => "bulk_warehouse_serial#{#count}.disabled =
bulk_warehouse_asset#{#count}.disabled =
!this.checked;"}%></td>
<td class="last">
<%= link_to "#{t("web-app-theme.delete", :default => "Delete")}", bulk_warehouse_path(bulk_warehouse), :method => :delete, :confirm => "#{t("web-app-theme.confirm", :default => "Are you sure?")}" %>
</td>
</tr>
</div>
<% #count = #count +1 %>
And in my controller I've something such as:
...
#count = 0
...
and this what is generated by web server log:
"warehouse"=>{"asset"=>"turiturira", "serial"=>"caricarira", "project_id"=>"1", "hardware"=>{"brand_id"=>"21"}, "hardware_id"=>"60", "state_id"=>"4", "position_id"=>"1", "logicalwarehouse_id"=>"3", "extra_id"=>"3"}, "bulk_warehouse_serial270"=>"t", "bulk_warehouse_asset270"=>"test", "enable_record2_page0"=>"1", "bulk_warehouse_serial2"=>"uela2", "bulk_warehouse_asset2"=>"bela2", "enable_record3_page0"=>"1"}_
e
Now, in my controller I need an action where I must check first all "enable_record#{#count}_page#{params[:page]}" values and then doing some actions. How can I make if statement in my controller? I was thinking something such as:
#count=0
#page = params[:page]
#count_max = 10
until #count == #count_max
if params[:warehouse][:enable_record#{#count}_page#{params[:page]}] == 1
...doing something...
end
#count=#count+1
end
but it gives me an surror; any suggestions?
This seems quite complicated for whatever it is you're trying to do, but I'll refrain from refactoring your approach. There is one standout in your code however -- it is the dynamic construction of the key you're using. You may want to construct it with a string then 'symbolize' it:
key = "enable_record#{#count}_page#{params[:page]}".to_sym
if params[:warehouse][key] == 1
...doing something...
end
Note: you also might reconsider the equality condition. The hash's value may not be an integer 1 as your code suggests and could actually be "1" (a string). Ensure both values are the same type (using either .to_s or .to_i) if there's any uncertainty.

Modifying attributes on the join model with accepts_nested_attributes_for

Simply, a Contact can have various associated Time Windows, which may or may not be Active as a Schedule. To wit:
Models
class Contact < ActiveRecord::Base
has_many :schedules
has_many :time_windows, :through => :schedules
accepts_nested_attributes_for :schedules, :allow_destroy => true
end
class TimeWindow < ActiveRecord::Base
has_many :schedules
has_many :contacts, :through => :schedules
end
class Schedule < ActiveRecord::Base
belongs_to :contact
belongs_to :time_window
end
View
<% TimeWindow.all.each do |tw| %>
<% schedule = Schedule.find_by_contact_id_and_time_window_id(#contact.id, tw.id)
schedule ||= Schedule.new %>
<p>
<%= f.label tw.description %>
<%= hidden_field_tag "contact[schedules_attributes][][id]", schedule.id %>
<%= check_box_tag "contact[schedules_attributes][][time_window_id]",
tw.id, #contact.time_windows.include?(tw) %>
<%= check_box_tag "contact[schedules_attributes][][active]", nil,
schedule.active %>
</p>
<% end %>
This submits something like this:
Parameters: { "commit" => "Update", "contact" => {
"group_ids" => ["2"], "enabled" => "1",
"schedules_attributes" => [ { "time_window_id"=>"1", "id"=>"46"},
{ "time_window_id" => "2", "id" => "42", "active" => "on" },
{ "time_window_id" => "3", "id" => "43"},
{ "time_window_id" => "4", "id" => "44", "active" => "on"}],
"last_name" => ...
The update action in the controller is basically stock, except to handle another instance of another related model which I coded using the "Handling Multiple Models" example from the Advanced Rails Recipes book.
According to this API doc, I think the above ought to work. However, nothing about the Schedules is getting updated. This shows up in the server log:
[4;35;1mSchedule Update (0.2ms)[0m [0mUPDATE `schedules` SET `updated_at` = '2010-09-30 20:39:49', `active` = 0 WHERE `id` = 42[0m
[4;36;1mSchedule Update (0.1ms)[0m [0;1mUPDATE `schedules` SET `updated_at` = '2010-09-30 20:39:49', `active` = 0 WHERE `id` = 44[0m
(NetBeans is giving me those stupid "[0m"'s in the output. I don't know what's wrong there.)
The SQL shows that the "active" boolean field is getting set to 0 where checked. How do I get this to correctly set the active bit?
As a followup, how would I organize this to get rid of the Schedule "connection" at all? I'm thinking I need to submit a :_delete with the Schedule from the form, but how would I do that conditionally when a checkbox is involved?
Thanks for any help you can provide. Rails is turning out to be a vast subject for me, and I want to do it "right." I'm really close here, but there's got to be a way to make this -- not just correct -- but elegant. The view code just feels way too cumbersome to be proper Rails. ;-)
I've kept trying different approaches to this problem, and I've come up with this, which works. Mostly. The only problem is that it doesn't handle NOT having a "Schedule" for each "Time Window". The form will render, and I'll get a disabled check_box (to prevent me from trying to delete something that isn't there), but I don't have a way to add it back, and submitting without it throws off the params hash (and causes Rails to give me an "Expected Hash (got Array)" error)
<% TimeWindow.all.each do |tw| %>
<% schedule = Schedule.find_by_contact_id_and_time_window_id(#contact.id, tw.id)
schedule ||= Schedule.new %>
<% f.fields_for "schedules_attributes[]", schedule do |sf| %>
<p>
<%= sf.label tw.description %>
<%= sf.hidden_field :id %>
<%= sf.check_box :_destroy, :disabled => schedule.new_record? %>
<%= sf.check_box :active %>
</p>
<% end %>
<% end %>
Note that the "schedules_attributes[]" array will automatically give you an existing ID within the braces in your HTML (which is nice), but the _attributes hash is expecting an "id" alongside the other attributes in order to make sense of the sub-hashes.
One of the big lessons I've learned here is that the "check_box_tag" method doesn't (seem to) give me a paired-up hidden field for Rails to parse in the unchecked case. I would have expected this. Adding one in by hand made a mess, which led me to finally giving into the "fields_for" method, and trying many incarnations before finding the appropriate syntax to get what I wanted out of it.
I've realized that my model isn't quite appropriate in this setup, so I'm going to change it, but I was so close to this answer, I wanted to at least get to the point of being able to see the end before I moved on.

Resources