Array method doesn't work in partial view - arrays

Rails5, none of the array methods are working in a partial view. If the recipient column is an array:
<%= #mail.recipients.first %>
Brings up:
ActionView::Template::Error (undefined method `first' for nil:NilClass):
It works fine if I do a binding.pry before it and do the same thing in the console. However, if I do:
<%= #mail.recipients %>
It gives me the full array. Just wondering if array methods are not accessible in views?
EDIT:
<%= #mail %>
gives me
#<Mail::ActiveRecord_Relation:0x007f3658bf4f38>
then i put it through
<% #mail.each do |mail| %>
and inside that i do
<%= mail %>
it gives me
<Mail:0x007f3668951618>
then i do
<%= mail.recipients.class %>
it gives me
Array
then i do
<%= mail.recipients.first %>
it gives me
ActionView::Template::Error (undefined method `first' for nil:NilClass):

You should have somthing like this :
class Mail < ActiveRecord::Base
has_many :recipients
....
end
class Recipient < ActiveRecord::Base
belongs_to :mail
....
end
And before calling mail.recipients.first, make sure you already defined to the 'mail' some 'recipients'.

Related

Puppet array loop in erb template

I have the following Yaml:
role::test::logos::filesanddata:
logo01.jpg:
title01: 'value01'
title02: 'value02'
title03: 'value03'
title04: 'value04'
title05: 'value05'
title06: 'value06'
title07:
- title07_01: value07_01
- title07_02: value07_02
- title07_03: value07_03
- title07_04: value07_03
- title07_05: value07_04
logo02.jpg:
title01: 'value01'
Through my Class (in Puppet code) am getting the following result:
["logo01.jpg", {"title01"=>"value01", "title02"=>"value02", "title03"=>"value03", "title04"=>"value04", "title05"=>"value05", "title06"=>"value06", "title07"=>[{"title07_01"=>"value07_01"}, {"title07_02"=>"value07_02"}, {"title07_03"=>"value07_03"}, {"title07_04"=>"value07_04"}, {"title07_05"=>"value07_05}]}]
["logo02.jpg", {"title01"=>"value01"}]
I am writing a template to split the data in multiple files (so far works). I am stuck on the item "title07", how should I continue the loop from there?
<%= #arraydata[0] %>
<% #arraydata.shift -%>
<% #arraydata.each do |item| -%>
<%= item['title01'] %>
<%= item['title02'] %>
<%= item['title03'] %>
<%= item['title04'] %>
<%= item['title05'] %>
<%= item['title06'] %>
<% item['title07'].each do |inner_item| -%>
<%= inner_item['title07']['title07_01'] %>
<% end -%>
<% end -%>
Its not clear to me what the end goal is however hopefully the below example should help you unblock the issues you have
given the following hiera data:
role::test::logos::filesanddata:
logo01.jpg:
title01: 'value01'
title02: 'value02'
title03: 'value03'
title04: 'value04'
title05: 'value05'
title06: 'value06'
title07:
- title07_01: value07_01
- title07_02: value07_02
- title07_03: value07_03
- title07_04: value07_03
- title07_05: value07_04
logo02.jpg:
title01: 'value01'
The following code assuming filesanddata = lookup('role::test::logos::filesanddata')
<% #filesanddata.each_pair do |file, titles| -%>
<%- titles.each_pair do |title, values| -%>
<%- if values.is_a?(String) -%>
<%= value %>
<%- elsif value.is_a?(Array) -%>
<%# As mentioned by John Bollinger you have an array %>
<%# of hashes so we have to unpack that as well %>
<%- values.each do |value_hash| -%>
<%- value_hash.each_pair do |_, value| -%>
<%= value %>
<%- end -%>
<%- end -%>
<%- end -%>
<%- end -%>
<% end -%>
would create a file with the following content
value01
value02
value03
value04
value05
value06
value07_01
value07_02
value07_03
value07_03
value07_04
value01
There seems to be confusion both in the data and in the ERB about how the data are structured. This YAML ...
title07:
- title07_01: value07_01
- title07_02: value07_02
- title07_03: value07_03
- title07_04: value07_03
- title07_05: value07_04
... provides an array of single-key hashes as the value of the host hash's 'title07' key. That's not necessarily wrong, but it's very suspicious. It's unclear what thge array layer is supposed to be doing for you, relative to making the data a single five-element hash.
Consider the ERB presented in light of that data structure. Here ...
<% item['title07'].each do |inner_item| -%>
... item['title07'] is an array of single-key hashes, so each inner_item is one of those hashes. The one key appearing in that hash varies from hash to hash, which makes these unnecessarily difficult to work with. None of the keys is 'title07', however, so this will break:
<%= inner_item['title07']['title07_01'] %>
You would need something along the lines of
<%= inner_item['title07_01'] %>
, but accounting for the fact that the key differs from inner_item to inner_item. If you really want to try to work with that, then you might find it useful to use each_with_index instead of each, so that you can construct the needed hash key from the array index. Alternatively, you could just iterate the inner hash to get the value.
But that demonstrates some of the infelicities of that data structure. Suppose that you instead structured the data as a single multi-key hash, bypassing the array level:
title07:
title07_01: value07_01
title07_02: value07_02
title07_03: value07_03
title07_04: value07_03
title07_05: value07_04
Then iterating over the entries probably gets you what you want more directly:
<% item['title07'].each do |_, value| -%>
<%= value %>
<% end -%>
Alternatively, since the keys have a computable form you can compute the keys with which to retrieve the leaf data:
<% 1...5.each do |i| -%>
<%= item['title07']["title07_0#{i}"] %>
<% end -%>
Similar could be made to work with your array-based structure, too, but the needed expression would be more complex (and is left as an exercise).

Print out collection as grouped items

So far I have a collection of programmes. A programme has an associated account and there are (currently) six different "types" of accounts that a programme can belong to.
I need to be able to dump out all the programmes but group them by the type of account they are.
Something like;
Alpha Type;
- Programme One
- Programme Two
- Programme Three
Beta Type;
- Programme Four
- Programme Five
Delta Type;
- Programme Six
So far all I have managed is to join the associated table and do an order by the account_type :name
<% #programmes.each do |programme| %>
<%= programme.account_type.name %>
<% end %>
Which will print out the programmes in a reasonable order but I don't know how to do the grouping.
I am using Postgres if that actually makes it easier? I am pretty new to both Ruby and Postgres
Actually seem to have cracked this one.
I stumbled over this post on Enumberable#group_by
Final code in the controller looks like this;
#programmes = "get all programmes.."
#account_names = #programmes.group_by{|programme| programme.account.name}
In the view I have;
<% #account_names.each_pair do |name, programmes| %>
<hr>
<strong><%= name %> programmes</strong>
<br>
<% programmes.each do |programme| %>
<i><%= programme.name %></i><br>
<% end %>
<% end %>
Remarkable!

Rails 4.1.4 ActionController param is missing or the value is empty: name

I am relatively new to learning how to code and I am really having problems understanding how to write the code for dealing with parameters in a private method in the controller of a Rails 4.1.4 app so that my app works correctly by allowing me to enter a new picture album name, save it to the db, and have it be persisted so that the name of the new album added shows correctly (currently, it does not work right at all). Can someone please help me? Any help at all would be greatly appreciated.
Here is my code for my albums controller:
class AlbumsController < ApplicationController
def index
#albums = Album.all
end
def new
#album = Album.new
end
def create
#album = Album.new(album_params)
#album.save
redirect_to albums_path
end
def show
#album = Album.find(params[:id])
end
def edit
end
def update
end
private
def album_params
params.require(:name).permit(:id, :category)
end
end
Also, here is my album model:
class Album < ActiveRecord::Base
belongs_to :user
has_many :photos
end
And here is my migration for the albums:
class CreateAlbums < ActiveRecord::Migration
def change
create_table :albums do |t|
t.string :name # Column for album name of type string
t.string :category # Column for photography category of type string
t.timestamps
end
end
end
Here is my code for my app/views/albums/index.html.erb file:
<div><%= link_to "Admin Access to Add New Album", new_album_path %></div>
<div><%= link_to "Home", root_path %></div>
<h1>Albums Gallery</h1>
<% #albums.each do |album| %>
<div><%= link_to album.name, "/albums/#{album.id}" %></div>
<% end %>
Here is my code from my app/views/albums/new.html.erb file where I use the form_for thing:
<h2>New Albums</h2>
<%= link_to "Back", albums_path %>
<%= form_for (#album) do |f| %>
<div>
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<%= f.submit "Add Album" %>
<% end %>
Everything up to the form_for part where I try to enter a new picture album name works. It's at this point where everything just unravels and won't work for me. Instead of accepting and then showing the new album by name, it displays "/albums/3" when it should display "Nature Scenes". I went into my rails console to see what was going on on the db level and the new albums are not being created and saved correctly. My output from the Rails console looks like this:
2.1.2 :007 > Album.all Album Load (0.2ms) SELECT "albums".* FROM "albums" => #, #, #,
, #
nil, category: nil, created_at: "2014-09-21 02:50:54", updated_at:
"2014-09-21 02:50:54">]>
2.1.2 :008 >
(Sorry about the copy/paste, but being too new at trying to learn how to code, I don't have enough reputation points on Stackoverflow to be allowed to simply post a screenshot yet.)
OK, never mind, I got it. I had the wrong value in the private method. I changed it to
def album_params
params.require(:album).permit(:id,:name, :category)
end
And now the app works fine (at least, so far - I have a long way to go to complete it).

How do you compare variables from different tables with ruby on rails?

For example, within a model/data-set/table (technical term?) called "microposts" if I have id and user_id columns, to compare the two sets I can use
Micropost.where("user_id = ?", id)
I am wondering, however, how to do the same thing with data from different data-sets/tables/models. In this particular scenario I am trying to find all instances where a user's community variable is equal to the community variable of any microposts. I'm attempting to match the content of the strings so that all microposts are rendered that have a community variable that matches the current user's community variable. These variables are in string form as #city + #state under the column "community" in the users's and microposts's model/datasets/table. Illustrated:
users table microposts table
user_id community micropost_id content community
1 FairfieldIowa 1 blub! FairfieldIowa
2 FairfieldIowa 2 Hiiy FairfieldIowa
3 Salt Lake CityUtah 3 wwowt! Salt Lake CityUtah
4 Salt Lake CityUtah 4 hey Salt Lake CityUtah
5 FairfieldIowa 5 sweet FairfieldIowa
I thought this might work in the User model:
def communityfeed
Micropost.where("community = ?", user.community)
end
However, it is incorrect because of syntax, logic, or because "user" does not define all users, I think.
Then I defined communityfeed_items in a pages_controller as:
def home
if logged_in?
#micropost = current_user.microposts.build
#communityfeed_items = communityfeed.paginate(page: params[:page])
end
end
But I get an undefined local variable or method communityfeed error
This could be because I'm not providing any user to use the method on. Perhaps simply using a variable for all users will solve my problem, but this is something I could not find. I've tried all_users, and user, with no success. Is it possible to compare variables to render a result in this way, and if so, what is the syntax to cycle through all user/microposts and check for these matches?
I also built several partials to function together to render the microposts, however, without the #communityfeed_items variable functioning correctly, they are of little use.
_communityfeed.html.erb
<% if #communityfeed_items.any? %>
<ol class="microposts">
<%= render partial: 'shared/communityfeed_item', collection: #communityfeed_items %>
</ol>
<%= will_paginate #communityfeed_items %>
<% end %>
_communityfeed_items.html.erb
<li id="<%= communityfeed_item.id %>">
<%= link_to gravatar_for(communityfeed_item.user), communityfeed_item.user %>
<span class="user">
<%= link_to communityfeed_item.user.name, communityfeed_item.user %>
</span>
<span class="content"><%= communityfeed_item.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(communityfeed_item.created_at) %> ago.
</span>
<% if current_user?(communityfeed_item.user) %>
<%= link_to "delete", communityfeed_item, method: :delete,
confirm: "You sure?",
title: communityfeed_item.content %>
<% end %>
</li>
If I have approached this problem in a severely inefficient/impossible way, I am open to suggestions.
Thanks for your time, generosity, and expertise.

Rails 3 array - add items with category then list items in category

As part of my Rails 3 app, I want the User to be able to click on links on other profiles/pages and have the string value of the link be added to an array belonging to that User's profile.
Specifically, what I am looking to do is populate a list of :todos for each profile depending on which todo they click. The idea is that each todo will fall within one of two categories: inside and outside. So clicking the links will push the value of the todo to either inside or outside. Then the User's profile will display a list of :todos inside and outside, and count the total of todos for that User's profile.
Since I'm a beginner to programming, I got some help here on SO about setting this up; however I need some help finishing it. I can't quite seem to connect all the dots. I've set up a join model but am not able to add the todo's string value, then list/count it in the profile. Here is my code:
profile.rb Model:
class Profile < ActiveRecord::Base
belongs_to :user
accepts_nested_attributes_for :user
has_many :profile_todos
has_many :todos, :through => :profile_todos
def add_todo_inside_item(item)
self.profile_todos.build :category => 'inside'
end
def add_todo_outside_item(item)
self.profile_todos.build :category => 'outside'
end
end
todo.rb Model:
class Todo < ActiveRecord::Base
belongs_to :profile
end
profile_todo.rb Model:
class ProfileTodo < ActiveRecord::Base
belongs_to :profile
belongs_to :todo
end
_create_todos.rb Migration:
class CreateTodos < ActiveRecord::Migration
def self.up
create_table :todos do |t|
t.string :name
t.timestamps
end
end
_create_profile_todos.rb Migration:
class CreateProfileTodos < ActiveRecord::Migration
def self.up
create_table :profile_todos do |t|
t.string :category
t.integer :profile_id
t.timestamps
end
end
Listing the todos in a User's Profile:
<div id="todos">
<p><%= #profile.first_name %> has <%= pluralize(#profile.profile_todos.count, 'goal') %>.</p>
<div id="todo-list">
<div class="todos_inside">
<p><%= #profile.profile_todos(:category => 'inside' %>.</p>
</div>
<div class="todos_outside">
<p><%= #profile.profile_todos(:category => 'outside' %>.</p>
</div>
</div>
</div>
add_item to #profile.todos:
<li><%= link_to "#", :class => 'button white' do %><%= #user.profile.stringtoadd %><% end %></li>
As #socjopata mentioned, you're going to need some sort of controller action to manage the creation and building of your ProfileTodo records. Since you already created a ProfileTodo join model, go ahead and create a ProfileTodosController.
More on controllers:
http://guides.rubyonrails.org/action_controller_overview.html
Your link_to tag should then make a remote call to the create action. In order to get everything to work properly, you'd most likely need to supply the controller with both the profile_id and topic_id in order to make the correct RESTful transaction, which means you'll have to supply a parameter hash to your link_to tag, which can get kinda messy if you use the url_options.
Look at passing in url_options:
http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to
Ultimately, you are creating a new ProfileTodo record, so I think it would be a better description of the work being done if you used a form_for tag that has hidden fields for the profile_id and the topic_id. You can also make forms remote in rails by supplying them with :remote => true
Assuming you make an accompanying controller and add RESTful resources to your config/routes.rb file, your form for each individual topic would look something like this:
<%= form_for(profile_todo_path, :remote=> true) do |f| %>
<%= f.hidden_field_tag :profile_id, :value => #user.profile.id %>
<%= f.hidden_field_tag :topic_id, :value => topic.id %>
<%= f.submit_tag topic.name %>
<% end %>
You can always style your forms, so if you only want a link to be displayed, that should be doable :)
You rather need a remote link pointing to some action, so you can manipulate your todos without refreshing the page. From the docs:
:remote => true - This will allow the unobtrusive JavaScript driver to
make an Ajax request to the URL in question instead of following the
link. The drivers each provide mechanisms for listening for the
completion of the Ajax request and performing JavaScript operations
once they’re complete
As for the other question, you can define scopes you'll use for displaying and counting objects:
http://api.rubyonrails.org/classes/ActiveRecord/NamedScope/ClassMethods.html

Resources