Undefined Method Error When Rendering Partial - ruby-on-rails

So, I entirely understand why one would normally receive an undefined method error, however, I am unsure why it is happening this particular time.
I have a partial:
submissions/_submission.html.erb
<div class="pure-u-1-2 rounded">
<%= link_to submission do %>
<div class="rounded" style="background-color: #B81324; color: #E6E6E6; margin: 10px; padding:5px;">
<div class="clear">Project: <%= submission.project.title %></div>
<div class="clear">Submitted By: <%= submission.submitter.username %></div>
<div class="clear">Amount: $<%= submission.price %></div>
<div class="clear">Description: <%= submission.description %></div>
</div>
<% end %>
</div>
This partial is used twice in my dashboard/index.html.erb
Once to render a collection of received submissions and again to render a collection of sent submissions:
dashboards/index.html.erb
<% if #received_submissions.length > 0 %>
<div class="pure-u-1" id="projects"><h3 class="red">Final Tracks Received (<%= #received_submissions.length %>)</h3>
<%= render :partial => :submission, :collection => #received_submissions %>
</div>
<% end %>
<% if #sent_submissions.length != 0 %>
<div class="pure-u-1" id="projects"><h3 class="red">Final Tracks Sent (<%= #sent_submissions.length %>)</h3>
<%= render :partial => :submission, :collection => #sent_submissions %>
</div>
<% end %>
However, rendering the received submissions works without ailment, and rendering the sent submissions errors out with:
undefined method `submissions' for #<PlayerProject:0x000001052730e8>
Here is the dashboards_controller also, just in case:
class DashboardsController < ApplicationController
before_filter :authenticate_user!
def index
#compact = current_user.projects.where.not(status: ['Deleted','Closed']).order("id desc")
#projects = current_user.projects.where.not(status: ['Deleted','Closed']).order("id desc")
#received_messages = current_user.received_messages
#received_submissions = current_user.projects.collect{|p| p.submissions }.flatten
#player = current_user.player_projects.collect{|pp| pp.project}
#sent_submissions = current_user.player_projects.collect{|ps| ps.submissions }.flatten
end
end
models/player_project.rb'
class PlayerProject < ActiveRecord::Base
belongs_to :project
belongs_to :player, :class_name => "User"
end
models/submission.rb
class Submission < ActiveRecord::Base
belongs_to :submitter, :class_name => "User"
belongs_to :recipient, :class_name => "User"
belongs_to :project
validates :amount_in_cents, :presence => true, length: { minimum: 2, :message => " must be more than $0" }
validates :description, :presence => { :message => " cannot be blank" }
validates :final_track_url, :presence => { :message => " Required" }
def price
sprintf "%.2f", (self.amount_in_cents.to_f/100.0)
end
def price=(val)
self.amount_in_cents = (val.to_f*100.0).to_i
end
def paid?
!!self.paypal_confirmation
end
end

I think your error will be model-level:
undefined method `submissions' for #<PlayerProject:0x000001052730e8>
Association
This typically suggests you don't have a particular association set up (I.E you're calling #model.x when x is not defined):
#sent_submissions = current_user.player_projects.collect{|ps| ps.submissions }.flatten
Although your player_projects is defined, I think your submissions attribute / association does not exist. Besides, you can use the pluck method to help this: current_user.player_projects.pluck(:submissions)
Firstly, do you have the submissions attribute in your table?
Secondly, if you don't, what are you trying to achieve with it? You don't typically have a plural column in your table (denotes multiple data stores). I would use an association on a join-model

Try this
<%= render "submission", :collection => #sent_submissions %>

Related

Complex Rails form with Nested Attributes (Rails 5)

I have a form, that is saving the main attribute, but not its nested attributes. I have dug into a lot of documents, and seem to be doing things correctly, but still get an error that my nested attributes "must exist".
My interview attributes are saving correctly to the database, but my logs show "Unpermitted parameters: student, parents"
My code is modified for brevity, but I will still try to be thorough enough to get some direction as to what might be going wrong ...
Models (which I include accepts_nested_attributes for :student, :parents)
:student is singular since it has a has_one relationship
:parents is plural since it has a has_many relationship
class Interview < ApplicationRecord
has_one :student
has_many :parents
accepts_nested_attributes_for :student, :parents
end
class Student < ApplicationRecord
belongs_to :interview
end
class Parent < ApplicationRecord
belongs_to :interview
end
Controller
class InterviewsController < ApplicationController
def index
#interviews = Interview.all
end
def show
#interview = Interview.find(params[:id])
end
def new
#interview = Interview.new
#interview.build_student
2.times { #interview.parents.build }
end
def create
#interview = Interview.new(interview_params)
if #interview.save
redirect_to #interview
else
render :action => 'new'
end
end
private
def interview_params
params.require(:interview).permit(:date_today, :date_contact, :purpose_of_call, :problems_start_date, :cause, :violence, :running_away, :police_contact, :suicide, :self_harm, :other_info, :testing, :hospitalization, :medications, :school_problems, :teacher_relationships, :parent_goals, :notes,
student_attributes: [:id, :name, :age, :height, :weight, :dob, :interview_id],
parents_attributes: [:id, :name, :relationship, :parentage, :address, :phone_home, :phone_work, :phone_mobile, :phone_mobile, :email, :employer, :notes, :interview_id] )
end
end
Form (important bits)
<%= form_for(#interview) do |f| %>
<p class="inline">
<%= f.label :date_today, 'Today\'s Date' %>
<%= f.date_select(:date_today, :order => [:month, :day, :year], :start_year => 2000, :end_year => Date.today.year) %>
</p>
<p class="inline float_right">
<%= f.label :date_contact, 'Initial Contact' %>
<%= f.date_select(:date_contact, :order => [:month, :day, :year], :start_year => 2000, :end_year => Date.today.year) %>
</p>
<%= f.fields_for :student do |student_form| %>
<p><%= student_form.text_field :name, placeholder: 'Name' %></p>
<p class="inline">
<%= student_form.label :age %>
<%= student_form.text_field :age %>
</p>
<p class="inline">
<%= student_form.label :height %>
<%= student_form.text_field :height %>
</p>
<p class="inline">
<%= student_form.label :weight %>
<%= student_form.text_field :weight %>
</p>
///// removed for brevity /////
<% end %>
<%= f.fields_for :parents do |parent_form| %>
<%= render 'parents', :f => parent_form %>
<% end %>
Parent Partial
<p>
<%= f.label :name, 'Name' %>
<%= f.text_field :name %>
</p>
//// and more of the same /////
Routes
resources :interviews do
resources :student
resources :parents
end
The website form (at it's current state) can be found here: www.compassconsultingwi.com/interviews/new
and the link to the github can be found here: https://github.com/plantoteachme/compassconsultingwi
Params returns this ..
Parameters: {"utf8"=>"✓", "authenticity_token"=>"nU4WM2RO5GJd36eaSLHMxhRQCOnY8EPjDhUdFBHlYGkcw6H7/Oc5y7kFx0HMU9nm5cc47ZZZBDW6oQ2QNF5yhA==", "interview"=>{"date_today(2i)"=>"11", "date_today(3i)"=>"16", "date_today(1i)"=>"2016", "date_contact(2i)"=>"10", "date_contact(3i)"=>"23", "date_contact(1i)"=>"2016", "student"=>{"name"=>"John", "age"=>"12", "height"=>"5 feet", "weight"=>"123 lbs", "dob(2i)"=>"3", "dob(3i)"=>"13", "dob(1i)"=>"2004", "strengths"=>"Great with his siblings", "weaknesses"=>"Lazy", "likes"=>"Food", "dislikes"=>"Chores", "medical_prolems"=>"ADD", "religous_training"=>"Catholic", "ethnic_issues"=>"none", "grade_level"=>"6"}, "parents"=>{"name"=>"Jamie", "relationship"=>"Mom", "parentage"=>"Strict", "address"=>"Miwaukee Wi", "phone_home"=>"555-1000", "phone_work"=>"555-1001", "phone_mobile"=>"555-1002", "email"=>"jj#jj.com", "employer"=>"Googleer", "notes"=>"PhD in Computer Science"}, "purpose_of_call"=>"Depression causing suicidal tendencies", "problems_start_date"=>"When we moved from Nigeria last year", "cause"=>"Relocating", "violence"=>"none", "running_away"=>"no", "police_contact"=>"no", "suicide"=>"Hasn't acted on it, but talks about it", "self_harm"=>"Minor bruising from \"sports\"", "other_info"=>"", "testing"=>"Yes, for ADD", "hospitalization"=>"no", "medications"=>"Regeline", "school_problems"=>"Getting bullied", "teacher_relationships"=>"Strained", "parent_goals"=>"Improve self awareness", "notes"=>"Our family was in Nigeria for mission work"}, "button"=>""}
Unpermitted parameters: student, parents
Try to use cocoon gem.
You can build a model object using link_to_add_association method of cocoon gem.
Also, you can remove object using link_to_remove_association
A fully working example here: https://github.com/nathanvda/cocoon/wiki/ERB-examples

Using jQuery Tokeninput within a nested form partial

I'm using jQuery Tokeninput as shown in this Railscast. I'd like to combine this functionality in a nested form but get the error
undefined method `artists' for #<SimpleForm::FormBuilder:0x007febe0883988>
For some reason its not recognizing the track parameter in my form builder which is stopping me to get a hold of albums I have on record.
<div class="input">
<%= f.input :artist_tokens, label: 'Featured Artists', input_html: {"data-pre" => f.artists.map(&:attributes).to_json} %>
</div>
Keep in mind this works in my track form but just not in my album form since its nested. What should I do to get this to work?
class ArtistsController < ApplicationController
def index
#artists = Artist.order(:name)
respond_to do |format|
format.html
format.json {render json: #artists.tokens(params[:q])}
end
end
end
Models
class Artist < ActiveRecord::Base
has_many :album_ownerships
has_many :albums, through: :album_ownerships
has_many :featured_artists
has_many :tracks, through: :featured_artists
def self.tokens(query)
artists = where("name like ?", "%#{query}%")
if artists.empty?
[{id: "<<<#{query}>>>", name: "Add New Artist: \"#{query}\""}]
else
artists
end
end
def self.ids_from_tokens(tokens)
tokens.gsub!(/<<<(.+?)>>>/) {create!(name: $1).id}
tokens.split(',')
end
end
class Albums < ActiveRecord::Base
attr_reader :artist_tokens
accepts_nested_attributes_for :tracks, :reject_if => :all_blank, :allow_destroy => true
has_many :albums_ownerships
has_many :artists, through: :albums_ownerships
def artist_tokens=(ids)
self.artist_ids = Artist.ids_from_tokens(ids)
end
end
class Track < ActiveRecord::Base
attr_reader :artist_tokens
belongs_to :album
has_many :featured_artists
has_many :artists, through: :featured_artists
def artist_tokens=(ids)
self.artist_ids = Artist.ids_from_tokens(ids)
end
end
class AlbumOwnership < ActiveRecord::Base
belongs_to :artist
belongs_to :album
end
class FeaturedArtist < ActiveRecord::Base
belongs_to :artist
belongs_to :track
end
Album Form
<%= simple_form_for(#album) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<h1>Tracks</h1>
<%= f.simple_fields_for :tracks do |track| %>
<%= render 'track_fields', :f => track %>
<% end %>
<div id='links'>
<%= link_to_add_association 'Add Field', f, :tracks %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Track Partial
<div class="field">
<%= f.input :name %><br>
</div>
<div class="input">
<%= f.input :artist_tokens, label: 'Featured Artists', input_html: {"data-pre" => f.artists.map(&:attributes).to_json} %>
</div>
JS
$(function() {
$('#track_artist_tokens').tokenInput('/artists.json', {
prePopulate: $("#track_artist_tokens").data("pre"),
theme: 'facebook',
resultsLimit: 5
});
});
UPDATE
As mentioned by nathanvda, I needed to use f.object in order for the artists to be recognized. So in my partial I now have:
<%= f.input :artist_tokens, label: 'Featured Artists', input_html: {"data-pre" => f.object.artists.map(&:attributes).to_json, class: 'test_class'} %>
In my js I also needed to call the token input method before/after insertion:
$(function() {
$('.test_class').tokenInput('/artists.json', {
prePopulate: $(".test_class").data("pre"),
theme: 'facebook',
resultsLimit: 5
});
$('form').bind('cocoon:after-insert', function(e, inserted_item) {
inserted_item.find('.test_class').tokenInput('/artists.json', {
prePopulate: $(".test_class").data("pre"),
theme: 'facebook',
resultsLimit: 5
});
});
});
The only remaining issue I have is the the tracks_attributes not being saved. I ran into an issue similar to this in the past in this post but the two main difference is the second level of nesting involved and that I used a join table within my nested form. I'm not entirely sure if or how any of that code would translate over but I believe this is most likely problem. As far as the permitted params of my albums_controller here's what they looks like.
def album_params
params.require(:album).permit(:name, :artist_tokens, tracks_attributes: [:id, :name, :_destroy, :track_id])
end
If you need to acces the object of a form, you need to write f.object, so I think you should just write f.object.artists.
Your "data-pre" => f.artists... is calling the artists method on f which is the form builder and doesn't have an #artists method.
Try this instead:
In the album form, change the render partial line to this:
<%= render 'track_fields', :f => track, :artists => #artists %>
And then use this in the track partial:
<%= f.input :artist_tokens, label: 'Featured Artists', input_html: {"data-pre" => artists.map(&:attributes).to_json} %>
UPDATED
Let's back up a step. From your code it looks like you need to populate a data-pre attribute with the attributes of a collection of artists.
The problem is you're calling f.artists where f is the FormBuilder and doesn't know anything about artists. This is why you're getting undefined method 'artists'...
The solution is make a collection of artists available to the view and its partials. One way to do this:
class AlbumsController < ApplicationController
...
def new
#album = Album.new
#artists = Artist.order(:name) # or some other subset of artists
end
...
def edit
#album = Album.find params[:id]
#artists = Artist.order(:name) # or perhaps "#artists = #album.artists", or some other subset of artists
end
end
and then in new.html.erb and edit.html.erb, pass #artists to the form partial:
... # other view code
<%= render 'form', album: #album %>
... # other view code
and then in your form partial:
... # other view code
<%= f.simple_fields_for :tracks do |track_form| %>
<%= render 'track_fields', :f => track_form %>
<% end %>
... # other view code
finally, in your track partial:
... # other view code
<div class="input">
<%= f.input :artist_tokens, label: 'Featured Artists', input_html: {"data-pre" => #artists.map(&:attributes).to_json} %>
</div>
... # other view code
Does that make sense?

Ruby on rails NoMethodError in custom controller action

Maybe someone could tell me how to create or correctly pass params from partial form_for to custom controller? Here is what i got so far:
Basically there are two classes: Scribbles (polymorphic - connected to local feeds) and local feeds. Trough command line, I can create scribbles, assign them to local feeds and display them in html. But creating them in trough different controller seems to be a rather tricky task. Any help would be appreciated.
Scribble.rb
class Scribble < ActiveRecord::Base
attr_accessible :post, :comments_attributes, :user_id, :posted_by, :localfeed_attributes
belongs_to :scribbled, :polymorphic => true
has_many :comments, :as => :commentable
accepts_nested_attributes_for :comments
end
localfeed.rb
class Localfeed < ActiveRecord::Base
attr_accessible :city, :scribble_id, :location_id, :localfeed_id, :scribble_attributes
belongs_to :location
has_many :scribbles, :as => :scribbled
accepts_nested_attributes_for :scribbles
validates :city, :presence => true, :uniqueness => true
Here is the error
NoMethodError in LocalfeedsController#newlocalscribble
undefined method `scribbles' for nil:NilClass
Rails.root: c:/workspace/uu2
Application Trace | Framework Trace | Full Trace
app/controllers/localfeeds_controller.rb:80:in `newlocalscribble'
localfeeds/show.erb.html
<% #newlocalscribble = #localfeed.scribbles.new %>
<%=render :partial => 'newlocalscribble.html.erb', :locals => {:newlocalscribble => #newlocalscribble, :localfeed => #localfeed}%>
localfeeds/_newlocalscribble.html.erb
<%= form_for #newlocalscribble, :remote => true, :url => url_for(:controller => 'localfeeds', :action => 'newlocalscribble') do |f| %>
<div class="">
<div class="field">
<%= f.text_area :post,:rows=>3,:placeholder=>"What's on your mind,#{current_user.full_name}?", :class=>"sribble-status-text" %>
<%= f.hidden_field :localfeed, :value => #localfeed.id%>
</div>
<div class="sribble-status-actions" id="newlocalscribble">
<%= f.submit "Share",:class=>"btn btn-info" %>
</div>
</div>
<% end %>
localfeeds_controller.rb
def newlocalscribble
#localfeed = Localfeed.find_by_id(params[:localfeed])
#user = current_user
#newlocalscribble = #localfeed.scribbles.create(params[:localscribble])
##localscribble.scribbled = #user
##localscribble.scribbled = #localfeed
end
def new
#localfeed = Localfeed.new
#feed = Localfeed.find_by_id(params[:localfeed])
#newlocalscribble = #feed.scribbles.new
end
routes.rb
resources :localfeeds do
resource :scribbles
collection do
post 'localscribble', :action => :newlocalscribble
end
end
Variables passed.
{"utf8"=>"✓",
"authenticity_token"=>"1+/Qu/o4EeEbpiL/g07XFa3756IQDo6ldmKH196EkSQ=",
"scribble"=>{"post"=>"hfdfs",
"localfeed"=>"1"},
"commit"=>"Share"}
most likely your variable params[:localfeed] is not set right. It is either nil or the value that came in is not in the database.
Solved It by passing the :locals => {:scribble => #scribble, :localfeed => #localfeed} to pass the right feed ID params to partial, and deleted the hidden field which created a duplicate and cause mass assignment error
Thank you Guys

acts as commentable: comment body formatting

I think I have a working version of acts_as_commenting_with_threading in my rails app, but it seems like the body of every comment is saved with weird formatting. How do I remove the formatting in my view so it only displays the text (and not the formatting)? For example, if I type the text "test comment," the body of the comment is saved as "---\nbody: test comment\n". I tried html_safe, but it didn't work.
step.rb
class Step < ActiveRecord::Base
extend FriendlyId
acts_as_commentable
friendly_id :position
has_ancestry :orphan_strategy => :adopt
attr_accessible :description, :name, :position, :project_id, :images_attributes, :parent_id, :ancestry, :published_on
belongs_to :project
has_many :images, :dependent => :destroy
accepts_nested_attributes_for :images, :allow_destroy => :true
validates :name, :presence => true
end
comments_controller.rb
class CommentsController < ApplicationController
def create
#project = Project.find(params[:project_id])
#commentText = params[:comment]
#user = current_user
#comment = Comment.build_from(#project.steps.find(params[:step_id]), #user.id, #commentText)
respond_to do |format|
if #comment.save
format.html {redirect_to :back}
else
format.html { render :action => 'new' }
end
end
end
end
show.html.erb:
<div class="stepComments">
<% if step.comment_threads.count >0 %>
<% step.comment_threads.each do |stepComment| %>
<% if stepComment.body.length>0 %>
<%= render :partial => 'comments', :locals => {:comment=> stepComment} %>
<% end %>
<br>
<% end %>
<% end %>
</div>
_comments.html.erb
<div class="comment">
<div class="userIcon">
<%= User.find(comment.user_id).username %>
<%= image_tag(User.where(:id=>comment.user_id).first.avatar_url(:thumb), :class=>"commentAvatar img-polaroid")%>
</div>
<div class="field">
<%= comment.body %>
</div>
</div>
This prints: "---\nbody: test comment\n"
The rails helper simple_format will print using the formatting rules so you will get just the text.
For example, <% simple_format(comment.body) %>
I couldn't figure out a way to do it besides just edited the string manually. This is what I ended up using:
<%= comment.body.slice((comment.body.index(' ')+1..comment.body.length)) %>
It seems very odd that there isn't some built in function for doing this...
It ended up being a quite simple solution; I had been calling the parameter incorrectly. It should have been:
#commentText = params[:comment][:body]

Cannot get simple_nested_form to submit data

I am trying to build a simple_nested_form in my Ruby on Rails app. When I submit my form I am getting some unknown error because it is just redirecting back to the form to input again. Here is the output in the rails server console for when I submit the form. It looks like there is some random "0" => thrown in there.
Parameters: {"machine"=>{"name"=>"2134", "ip_adress"=>"2", "machine_employees_attributes"=>{"0"=>{"machine_id"=>"1", "employee_id"=>"2"}}}, "commit"=>"Create Machine"}
I have a machine model which has_many :machine_employees
and a machineemployee model which belongs_to :machine
Do you have any idea why this 0 => could be appearing because I think it is what is giving me the issues.
Here is the code for my models.
Machine
class Machine < ActiveRecord::Base
# Relationships
has_many :machine_employees
has_many :employees, :through => :machine_employees
accepts_nested_attributes_for :machine_employees, :reject_if => lambda{ |me| me[:employee_id].blank? }
attr_accessible :ip_adress, :name, :machine_employees_attributes
# Validations
validates_presence_of :name, :ip_adress
end
MachineEmployee
class MachineEmployee < ActiveRecord::Base
before_validation :set_default
# Relationships
belongs_to :machine
belongs_to :employee
attr_accessible :employee_id, :machine_id, :end_date, :start_date
# Validations
validates_presence_of :employee_id, :machine_id, :start_date
private
# Callback Methods
def set_default
self.start_date = Date.today
self.end_date = nil
end
end
New Machine Form
<div class="row-fluid">
<div class="span3">
<h1>Add a Machine</h1>
<br />
<%= simple_nested_form_for #machine do |f| %>
<%= render "machine_fields", :f => f %>
<%= f.button :submit %>
<%= link_to 'Back', machines_path %>
</div>
<div class="span4">
<h4>Assign an Employee to This Machine</h4>
<%= f.simple_fields_for :machine_employees do |me_form| %>
<!-- render nested machine_employee fields-->
<%= render "machine_employee_fields", :f => me_form %>
<% end %>
</div>
<% end %>
</div>
Machine Employee Fields Partial
<%= f.input :machine_id, :as => :hidden, :input_html => { :value => #machine.id } %>
<%= f.input :employee_id, collection: #employees, :id => :name, :prompt => "Select ..." %>
The 0 is thrown in there because the machine model has_many machine_employees. When you use nested forms, it passes a pseudo-array for has_many relations. So, if you tried to submit 2 machine employees, your hash would look like this:
Parameters: {"machine"=>{"name"=>"2134", "ip_adress"=>"2", "machine_employees_attributes"=>{
"0"=>{"machine_id"=>"1", "employee_id"=>"2"},
"1"=>{"machine_id"=>"1", "employee_id"=>"3"}
}
}, "commit"=>"Create Machine"}
This way you can access the machine_employees passed from the form by doing params[:machine][:machine_employees_attributes][0] or params[:machine][:machine_employees_attributes][1]. Note that if this was a has_one relationship, then the machine_employees_attributes key would be changed to machine_employee_attributes and there would be no numerical index.
I suspect the problem is that your machine model must accept_nested_attributes_for :machine_employees and must also have attr_accessible :machine_employees_attributes.

Resources