Unable to traverse one-to-one relationship in Rails - relationship

I've got an application where each user has one keyholder, who is allowed to access their account. These are separate models. I've set up the one-to-one relationship within the models, however when I try and use this within the views, I am getting the error of 'undefined method 'id' for nil:NilClass. I've used relationships and traversed them many times before, but I don't understand why this is happening, so please can someone explain?
The only thing that I have done differently from normal is to use Devise to generate the keyholder model rather than scaffolding it as I normally would.
Thanks!
user.rb:
has_one :keyholder
keyholder.rb:
belongs_to :user, dependent: :destroy
And neither of these views work:
keyholders/index.html.erb
<% #keyholders.each do |keyholder| %>
<tr>
<td><%= keyholder.id %></td>
<td><%= keyholder.username %></td>
<td><%= keyholder.user.id %></td>
<td><%= link_to 'Show', keyholder %></td>
<td><%= link_to 'Edit', edit_keyholder_path(keyholder) %></td>
<td><%= link_to 'Destroy', keyholder, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
or keyholder/show.html.erb
<p>
<strong>ID:</strong>
<%= #keyholder.id %>
</p>
<p>
<strong>Username:</strong>
<%= #keyholder.username %>
</p>
<p>
<strong>Keyholder for:</strong>
<%= #keyholder.user.first_name %> <%= #keyholder.user.last_name %>
</p>
<p>
<strong>User ID:</strong>
<%= #keyholder.user.id %>
</p>
Controller code:
def index
#keyholders = Keyholder.all
end
def show
#keyholder = Keyholder.find(params[:id])
end

I tried everything to check where any errors could be - for example checking that both the keyholder's user_id and the user's keyholder_id were both integers etc.
In case anyone is reading this and wants the code to do so, it is:
#model.column_for_attribute('column_name').type
I didn't manage to fix this in the end - luckily I was just starting out with this app, so started again and scaffolded both models before adding Devise to them, and it now works fine having done everything else the same.

Related

Rendering in Rails erb of a each_with_index loop through a JSONB array results in duplicates

I am trying to render the following in a view but the outcome (day and array) is duplicated. This seems to work in a console and removing the time helpers does not help. I suspect an ERB thing.
The business_hours are stored as JSONB.
Any hints of what I have missed appreciated.
company.schedules.last.business_hours returns
=> {"monday_opens_at"=>"08:00:00", "sunday_opens_at"=>"09:00:00", "monday_closes_at"=>"20:00:00", "sunday_closes_at"=>"18:00:00"}
<table class="table table-sm table-borderless text-sm mb-0">
<% if company.schedules.last.business_hours? %>
<% I18n.t('date.day_names').each do |day| %>
<% %w[opens_at closes_at].each_with_object([]) do |time_type, to_return| %>
<% #hours = to_return << company.schedules.last.business_hours["#{day.downcase}_#{time_type}"]
#hours.compact.tap do |hours| %>
<tr>
<th class="pl-0"><%= "#{day}" %></th>
<td class="pl-0 pr-0 text-right"><%= "#{time_helper(hours)}" %></td>
</tr>
<% end %>
<% end %>
<% end %>
<% else %>
<p> no data available</p>
<% end %>
</table>
The to_return parameter on the each_with_object loop is cumulative. When time_type is opens_at, you attribute the business hours to to_return with << and then you set #hours with the contents of to_return.
In the second run, when time_type is closes_at, you are setting #hours with the contents of to_return, which will be the business hours from the first loop plus the business hours from the second (because of the <<). That may be causing the duplication.
Also, we should investigate the tap, it should work with a simple each in there.

How to mark the simple_form checkbox based on a Array object?

The Rails view has two parameters
list_of_attributes = ["a1", "a2", "a3", "a4"]
user_selections = ["a2", "a4"]
I am able to display the appropriate checkboxes and any associated user selections using the following simple_form definition
<% list_of_attributes.each do |item| %>
<label>
<%= check_box_tag "user_selections[]", item, user_selections.include?(item) %>
<%= item %>
</label>
<% end %>
How can I define the above behavior using simple_form f.input syntax? With the following definition, I am able to display the appropriate checkboxes, but any user selections is not 'checked'.
<%= f.input key, as: :check_boxes, collection: list_of_attributes,
:label => key, class: "form-control" %>
Thanks for your help.
Adding checked attribute got the f.input definition functional.
<%= f.input key, as: :check_boxes,
collection: list_of_attributes,
:label => key,
checked: user_selections,
class: "form-control" %>
<% end %>
Try this. This worked for me using bootstrap CSS. Check line 25 in my github repo here
<div class="form-group">
<div class="row">
<div class="col-sm-offset-3 col-sm-8">
<%= f.collection_check_boxes :your_model_ids, Your_model.all, :id, :list_of_attributes do |cb| %>
<% cb.label(class: "checkbox-inline input_checkbox") {cb.check_box(class: "checkbox") + cb.text} %>
<% end %>
</div>
</div>
</div>
And then use this in your CSS file for the custom input_checkbox class above
.input_checkbox input {
width: auto !important;
}

Why is fields_for rendering different indexes in the same form?

I’m using Rails 4.2.3. In my view, I make use of the “fields_for” directive. Notice I use it twice (“f.fields_for :my_object_times”) below …
<div class="field">
<%= f.label "Time" %> <span class="required">*</span><br>
<%= select_tag('my_object[hour]', options_for_select((0..99).to_a.map { |i| i.to_s.rjust(2,'0')}), {:prompt => 'Select Hour'} ) %> hrs
<%= select_tag('my_object[minute]', options_for_select((0..60).to_a.map { |i| i.to_s.rjust(2,'0')}), {:prompt => 'Select Minutes'} ) %> min
<%= select_tag('my_object[second]', options_for_select((0..60).to_a.map { |i| i.to_s.rjust(2,'0')}), {:prompt => 'Select Seconds'} ) %> sec
<%= f.fields_for :my_object_times do |mot| %>
<%= mot.hidden_field :time_in_ms %>
<% end %>
</div>
<div class="field">
<%= f.fields_for :address do |addr| %>
<%= addr.label :address %><br>
City: <%= addr.text_field :city %>
<%= select_tag :state, options_for_select(us_states) %>
<%= country_code_select(:country, :country_id,
nil,
{:include_blank=>false},
{:style=>''}
) %>
<% end %>
</div>
<%= f.fields_for :my_object_times do |rt| %>
<div class="field">
<%= rt.label :overall_rank %><br>
<%= rt.text_field :overall_rank %>
</div>
<div class="field">
<%= rt.label :age_group_rank %><br>
<%= rt.text_field :age_group_rank %>
</div>
<div class="field">
<%= rt.label :gender_rank %><br>
<%= rt.text_field :gender_rank %>
</div>
<% end %>
But when my form gets rendered, the array index on the attributes are displayed differently (one is “0” and the other is “1”) …
<input type="hidden" name="my_object[my_object_times_attributes][0][time_in_ms]" id="my_object_my_object_times_attributes_0_time_in_ms" value="252008000">
…
<input type="text" name="my_object[my_object_times_attributes][1][overall_rank]" id="my_object_my_object_times_attributes_1_overall_rank">
How do I modify my view code so that both attributes get rendered with the “0” index? Note I would prefer to leave the order of my elements on my page exactly as they are.
Two solutions come to mind:
1 - Group your hidden_field (since it's not being shown) with your second form_for which will make it a non-issue and be more elegant.
2 - build your my_object_times object in your controller so when you call the fields_for method you can refer that object which should (I haven't tested it) give it the same reference.
If none of the two options are possible, I'd look at the code and see if there's any way you can refactor to make it work.

How to select options from array with form_tag and checkboxes

I have an array #sources that contains names (strings) of sources. In a view I want to list every source with a checkbox in a remote form. Then in the linked controller action I would like to have an array in the params hash, containing only those sources, that the user has checked before submitting.
I tried doing that manually, like so:
<%= form_tag select_sources_user_wordsearch_path(#user, #wordsearch), {method: :post, remote: true} do %>
<% #sources.each do |source| %>
<div class="form-group">
<div class="checkbox">
<label class="pull-left">
<input type="checkbox" class="pull-right"> <%=source%>
</label>
</div>
</div>
<% end %>
<div class="form-group">
<%= submit_tag "Start Search",id:"search_commit", class: "btn btn-primary" %>
</div>
<% end %>
But when submitting the form, I don't even see a params hash:
Started POST "/users/1/wordsearches/77/select_sources" for 127.0.0.1 at 2015-08-15 16:18:06 +0200
Processing by WordsearchesController#select_sources as JS
Parameters: {"utf8"=>"✓", "commit"=>"Start Search", "user_id"=>"1", "id"=>"77"}
So I was looking around to see what's going on with the form_tag helper and check_box_tag. And in check_box_tag's API page (see comments) I found that it is possible to pass a collection into it and receive the result of the selection in an array in the params hash. Basically, what I described above.
I am wondering how this would be done inside a form_tag for a remote form, with an array (instead of a collection)?
In the form_tag API page I couldn't find anything about how the data is transferred to the controller. In the check_box_tag there is nothing mentioned about how to handle collections.
Can anyone tell me how this is done "the Rails way"?
It has to be easier than I think..
First question: why don't you use the the form_for helper? Could be something like form_for #wordsearch, url: select_sources_user_wordsearch_path(#user, #wordsearch), {method: :post, remote: true} do.
You may also have a look at the collection_check_boxes helper in the API.
Afaik this can only be used with form_for and the corresponding form object.
<%= form_for #wordsearch do |form| %>
<%= form.collection_check_boxes(:source_ids, #sources, :id, :labeling_method ) %>
<% end %>
Assuming #sources is some kind of an object. In your case
<%= form_for #wordsearch do |form| %>
<%= form.collection_check_boxes(:sources, #sources, :to_s, :to_s ) %>
<% end %>
could work as well. (Did not try it!)
Another way would be to just send the values manually like so:
<% #sources.each do |source| -%>
<%= check_box_tag "wordsearch[sources][]", source -%>
<%= source -%>
<% end -%>
Hope this helps.

Strange Eco Template Behavior

I am using Backbone and Eco templates in my Rails application. My template has the following code:
<% #collection.each (model)-> %>
<% console.log model.get('name') %>
<p><%= model.get('name') %></p>
<p><%= model.get('description') %></p>
<% end %>
For some reason, the HTML is blank. The name and description are not displayed. However, the console.log method outputs the correct data. What am I doing wrong?
Well I figured out the missing character. Apparently, Eco templates require a colon after the arrow:
<% #collection.each (model)->: %>
Not sure why this is the case. It's never mentioned in the readme.

Resources