NoMethodError with deeply nested models - ruby-on-rails

I am not sure if I'm structuring my application corretly (I've been learning Rails for 2 months now) but I am building a pretty deeply nested application that looks like this:
user has_many accounts > accounts has_many characters > characters has_many items
So it's 4 levels deep (that's the plan at least).
I'm currently at characters and I'm having trouble creating the form which is throwing up this error: undefined method 'characters' for nil:NilClass (screenshot).
Here's the project on github: https://github.com/imjp/d2shed
characters_controller.rb
class CharactersController < ApplicationController
def create
#user = User.find(params[:user_id])
#account = Account.find(params[:account_id])
#character = #account.characters.create(params[:character])
redirect_to root_url
end
end
character.rb
class Character < ActiveRecord::Base
attr_accessible :name, :type
belongs_to :account
end
_form.html.erb
<%= form_for([#account, #account.characters.build]) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.radio_button(:type, "SC") %>
<%= f.label(:type, "SC") %>
<%= f.radio_button(:type, "HC") %>
<%= f.label(:type, "HC") %>
<%= f.radio_button(:type, "SCL") %>
<%= f.label(:type, "SCL") %>
<%= f.radio_button(:type, "HCL") %>
<%= f.label(:type, "HCL") %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

You get this error because you don't define #account in the users controller in the show action,
class UsersController < ApplicationController
...
def show
#user = User.find(params[:id])
#account = #user.accounts.first # Otherwise #account == nil
...
end
...
end
Also, the route in your form don't look right.
The create action for the Character resource is like this in the routes:
POST /:user_id/accounts/:account_id/characters
So you need to provide, :user_id, :account_id, and character
like this:
<%= form_for [#user, #account, #account.characters.build] %>

Related

I am using the simple_form gem in rails 7 and I am trying to get the options to show what I want intstead of what is given

I am new to ruby on rails and need to use the simple_form gem. I have an association that gets the value that I want so far but when I show the form what I see is something like: #User:0x000001830e64f9a0
I want to change that to whatever I choose (value will be from a database) to show
form.html.erb
<%= simple_form_for(#player) do |f| %>
<%= f.error_notification %>
<%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
<div class="form-inputs">
<%= f.association :User, as: :select %>
<%= f.input :fname %>
<%= f.input :lname %>
<%= f.input :position %>
<%= f.input :club %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Part of player controller
class PlayersController < ApplicationController
before_action :set_player, only: %i[ show edit update destroy ]
# GET /players or /players.json
def index
#players = Player.all
end
# GET /players/1 or /players/1.json
def show
end
# GET /players/new
def new
#player = Player.new
#user = User.select(:username)
end
User model
class Player < ApplicationRecord
belongs_to :User
end
Player model
class User < ApplicationRecord
end
as max has commented, change :User in both your form and belongs_to relation to :user
Regarding the value of the player instead of getting the value of the object player, you should map your collection with the specific field that you want to display such as:
Player.all.map(&:fname) for first name
or
Player.all.map(&:whatever_value_you_want_to_show_from_DB)

undefined method `reviews' for nil:NilClass

I'm trying to create a reviews model for company pages. For this I have:
Models
user.rb
has_many :reviews
class Review < ActiveRecord::Base
belongs_to :user
belongs_to :company
end
class Company < ActiveRecord::Base
has_many :reviews
end
My reviews controller is:
def create
#company = Company.find_by_slug(params[:id])
#review = #company.reviews.create(params[:review])
#review.save
redirect_to company_path(#company)
end
and I have this code in the company show page:
<% #company.reviews.each do |review| %>
<p>
<strong>Title:</strong>
<%= review.title %>
</p>
<p>
<strong>Avantage:</strong>
<%= review.avantage %>
</p>
<p>
<strong>Inconvenient:</strong>
<%= review.inconvenient %>
</p>
<% end %>
</br>
<%= form_for([#company, #company.reviews.build]) do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :avantage %><br>
<%= f.text_area :avantage %>
</div>
<div class="field">
<%= f.label :inconvenient %><br>
<%= f.text_area :inconvenient %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
However, when I go to a specific company page and try to create a review for this company I'm getting this error message undefined method reviewsfor nil:NilClass
Instead of #company = Company.find_by_slug(params[:id]) use this code #company = Company.friendly.find(params[:company_id])
There are a couple of things you may find useful:
If you're using Rails 4, you may encounter a further problem. In the third line of your create method, you are using unsecure params directly in a .create call. Check out the Rails Guide page on "strong params".
If you implement strong parameters as mentioned above, you should probably deliberately omit the company_id field from the list of permitted params.
Assuming your users are allowed to write a review for any company in your system, it might be simpler for you to embed the company_id as a hidden field in your form. This would allow you to also simplify the controller method. For example:
# _form.html.erb
<%= form_for(#review) do |f| %>
<%= f.hidden_field :company_id, value: #company.id %>
...bla bla bla
<% end %>
Then, in your reviews_controller...
# reviews_controller.rb
def create
#review = Review.new(approved_params)
if #review.save
flash[:success] = 'Review created!'
else
flash[:error] = "Review wasn't saved"
end
#company = #review.company
redirect_to #company
end
def approved_params
params.require(:review).permit(:title, :avantage, :inconvenient, :company_id)
end
In your companies_controller, you should add this to your show method
# companies_controller.rb
def show
#company = Company.find(params[:id]
# add this line below...
#review = Review.new
end
I hope this helps.

Rails 4 Nested Form.

I am building a dynamic form for a client. A form has many form questions which has many form answers. As of now, I am able to create everything nicely in Active Admin and have it displaying through the show action on the app interface. Here is the problem I have. I want to display the form title (which is working), along with the form questions (which is working), along with input fields to submit new form answers on the fly (which is the part that is not working). I feel like I have exhausted everything when it comes to nested forms. I will post my code below.
Form
<%= form_for #form do |f| %>
<div class="field">
<h1><%= #form.name %></h1>
</div>
<%= f.fields_for :form_questions do |ff| %>
<div class="field">
<%= ff.label :title %>
<%= ff.text_field :form_answers %>
</div>
<% end %>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Here is the models
class Form < ActiveRecord::Base
has_many :form_questions, dependent: :destroy
accepts_nested_attributes_for :form_questions, allow_destroy: true
end
class FormQuestion < ActiveRecord::Base
belongs_to :form
has_many :field_types
has_many :form_answers, dependent: :destroy
accepts_nested_attributes_for :field_types
accepts_nested_attributes_for :form_answers
end
class FormAnswer < ActiveRecord::Base
belongs_to :form_question
end
And my form controller
class FormsController < ApplicationController
def new
#form = Form.new
# form_questions = #form.form_questions.build
# form_answers = form_questions.form_answers.build
end
def create
#form = Form.new(form_params)
end
def index
#forms = Form.includes(:form_questions).all
end
def show
#form = Form.find(params[:id])
end
def edit
#form = Form.find(params[:id])
end
def form_params
params.require(:form).permit(:id, :name, form_questions_attributes: [:title, form_answers_attributes: [:answer]])
end
end
Firstly,you should uncomment those two lines in your new method.I guess they are correct.
def new
#form = Form.new
#form_questions = #form.form_questions.build
#form_answers = #form_questions.form_answers.build
end
And in your create action,you are not saving the data
def create
#form = Form.new(form_params)
if #form.save
.....
else
.....
end
end
Secondly,your form code should look like this
<%= form_for #form do |f| %>
<div class="field">
<h1><%= #form.name %></h1>
</div>
<%= f.fields_for #form_questions do |ff| %>
<div class="field">
<%= ff.label :title %>
<%= ff.text_field :title %>
</div>
<%= ff.fields_for #form_answers do |fa| %> #Here comes the important step
<div class="field" %>
<%= fa.label :answer %>
<%= fa.text_field :answer %>
</div>
<% end %>
<% end %>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>

undefined method `model_name' for NilClass:Class - where's the error?

I've been trying to figure this out for a while now but I can't see the error.
When I go to jobs/new. Instead of seeing the form that I specified in my view. I'm receiving - undefined method model_name' for NilClass:Class
Here's my controller where im defining the new action.
class JobsController < ApplicationController
respond_to :html, :json
...
def new
#jobs = Job.new
respond_with #jobs
end
And my view.
<%= form_for(#jobs) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :client %><br />
<%= f.text_area :client, rows: 6%>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And my model.
class Job < ActiveRecord::Base
belongs_to :client
end
The source of the error is line 1 according to the error message in my browser. But I can see where I'm going wrong?
This will work but has no sense :)
def new
#jobs = Job.new
#jobs.client= CLient.new
respond_with #jobs
end
What do you want to put into your client textarea?

Mongoid creating embedded document from a view

I am trying to add a embed a Profile into a User and I keep getting this error.
Access to the collection for Profile is not allowed since it is an embedded document, please access a collection from the root document.
I am sure it's a simple problem to fix but I have no clue how to do it. I am very new with RoR so things are still a little confusing. Here is my code.
Models/Profile
class Profile
include Mongoid::Document
attr_accessible :handle, :description
field :handle
field :description
embedded_in :user
end
Controllers/Profile
class ProfileController < ApplicationController
def create
#user = current_user
#profile = #user.profile.create!(params[:profile])
redirect_to dashboard_path
end
end
Views/profile/new
<h1>Create Profile</h1>
<%= form_for [:current_user, Profile.create] do |f| %>
<div class="field">
<%= f.label :handle %>
<%= f.text_field :handle %>
</div>
<div class="field">
<%= f.label :description %>
<%= f.text_area:description %>
</div>
<p class="button"><%= f.submit %></p>
<% end %>
You cannot use Profile.create in your views.html.erb because Profile is embedded in a user. So you need to do something like current_user.build_profile
<%= form_for [:current_user, current_user.build_profile] do |f| %>
should work
try
#user = current_user
#profile = Profile.new(params[:profile])
#user.profile = #profile
#user.save
# or #profile.save

Resources