Rails 5 - has_many through: association and select in view - ruby-on-rails

How I can get selected values in select helper with has_many through: association and nested form?
app/models/team.rb
class Team < ApplicationRecord
has_many :team_users
has_many :users, through: :team_users
accepts_nested_attributes_for :team_users, allow_destroy: true, reject_if: proc { |a| a['user_id'].blank? }
end
app/models/user.rb
class User < ApplicationRecord
has_many :team_users
has_many :teams, through: :team_users
accepts_nested_attributes_for :team_users, :teams, allow_destroy: true
end
app/models/team_user.rb
class TeamUser < ApplicationRecord
belongs_to :team
belongs_to :user
accepts_nested_attributes_for :team, :user, allow_destroy: true
end
app/controllers/teams_controller.rb
class TeamsController < ApplicationController
before_action :set_team, only: [:show, :edit, :update, :destroy]
before_action :set_team_users, only: [:new, :edit]
before_action :set_new_team_user, only: [:new, :edit]
before_action :set_team_users_collection, only: [:new, :edit]
...
# GET /teams/1/edit
def edit
end
...
private
# Use callbacks to share common setup or constraints between actions.
def set_team
#team = Team.find(params[:id])
end
def set_team_users
#team_users = #team.team_users
end
def set_new_team_user
#new_team_user = #team.team_users.build
end
def set_team_users_collection
#team_users_collection = User.all.collect { |p| [ p.name, p.id ] }
end
def team_params
params.require(:team).permit(
:name,
:parent_id,
team_users_attributes: [:_destroy, :id, :user_id]
)
end
end
app/views/teams/_form.html.erb
<%= form_for(#team) do |f| %>
...
<% f.fields_for #team_users do |team_user_f| %>
<%= team_user_f.select(:user_id, #team_users_collection, { include_blank: true }, class: 'form-control custom-select', style: 'width:auto;') %>
<% end %>
...
<% end %>
This generates the following error:
undefined method 'user_id' for #<TeamUser::ActiveRecord_Associations_CollectionProxy:0x007f90a13a3f70>

I believe you may have your arguments wrong in the select method:
<%= team_user_f.select(:team_user, :user_id, #team_users_collection, { include_blank: true }, class: 'form-control custom-select', style: 'width:auto;') %>
See if that works

Related

How to update a nested form - Ruby on Rails

I am having an issue with my update method in my recipes controller where I cannot create a new category. Category is a nested resource within recipes. This is my update method
def update
if current_user.id != #recipe.category.user_id
flash.now[:notice] = "You cannot update a recipe that you did not author."
redirect_to recipes_path
else
#recipe.update(recipe_params)
flash.now[:notice] = "#{#recipe.title} has been updated."
redirect_to recipe_path
end
if #category
recipe.build_category
end
end
I just recently added the if #category recipe.build_category but that didn’t do anything.
This is my recipe strong params:
def recipe_params
params.require(:recipe).permit(
:title,
:description,
:category_id,
category_attributes: [:name],
instructions_attributes: [:id,
:step, :_destroy
]
)
end
And my recipes controller before actions:
before_action :redirect_if_not_logged_in
before_action :find_recipe, only: [:show, :edit, :update, :destroy]
before_action :find_category, only: [:index, :new, :create]
I also have this language in my recipes _form:
<%= f.fields_for :category, recipe.build_category do |cb| %>
<div style="margin-left:30px">
<%= cb.label :name %>
<%= cb.text_field :name %>
</div>
<% end %>
and then this in my recipes edit.html.erb
<%= render partial: "form", locals: {recipe: #recipe, category: #category, button_name: "Update Recipe"}%>
These are my recipes & categories routes:
resources :recipes, only: [:index, :show, :new]
end
resources :recipes do
resources :categories, only: [:index, :new, :create]
end
resources :users, only: [:show, :new] do
resources :recipes, only: [:index]
end
This is my recipes model:
belongs_to :category
accepts_nested_attributes_for :category, reject_if: :all_blank
has_many :instructions, dependent: :destroy
accepts_nested_attributes_for :instructions, reject_if: :all_blank, allow_destroy: true
validates :title, presence: true
validates :instructions, presence: true
validates :description, presence: true
end
Does anyone know why I wouldn’t be able to create the category within an existing recipe?
**Side note - my flash errors are also not working. Thanks in advance for any help.

Nested resource #index action not working as expected

I have Producers nested inside of Islands, however my Producer#Index shows all the Islands. I expect to have each Producer index view to only list Producers for the parent Island. Please help!
routes.rb
Rails.application.routes.draw do
devise_for :users
root to: 'islands#index'
resources :islands do
resources :producers
end
end
islands.rb
class Island < ApplicationRecord
has_many :producers, dependent: :destroy
accepts_nested_attributes_for :producers
validates :island_name, uniqueness: true, presence: true
validates :island_country, presence: true
validates_associated :producers
end
producers.rb
class Producer < ApplicationRecord
belongs_to :user
belongs_to :island
end
producers_controller.rb
class ProducersController < ApplicationController
skip_before_action :authenticate_user!, only: [ :index ]
before_action :set_island
before_action :set_producer, only: [ :show, :edit, :update, :destroy]
def index
#producers = Producer.where(island_id: params[:island_id])
#producers = policy_scope(Producer)
end
...
private
def set_island
#island = Island.find(params[:island_id])
end
def set_producer
#producer = #island.producers.find(params[:id])
authorize #producer
end
def producer_params
params.require(:producer).permit(:producer_name, :email, :address1, :address2, :postal_code, :city, :country, :island_id)
end
end
producers/index.html.erb
<div class="container">
<h1>Producers from <%= #island.island_name %></h1>
<ul>
<% #producers.each do |producer| %>
<div class="container">
<h5><%= producer.producer_name %></h5>
<h5><%= link_to "details", island_producer_path(producer.island, producer)%></h5>
</div>
<% end %>
</ul>
</div>
You need to pass the scope into policy_scope:
class Island < ApplicationRecord
has_many :producers
end
class ProducersController < ApplicationController
def index
#producers = policy_scope(#island.producers)
end
end

Why does simple_form raise an "No route matches [POST] "/tenants"" error with nested resources

I am trying to make a simple form for creating a new Tenant, knowning that when you create a tenant, a Devise User(with "role: "tenant") has to be created at the same time. But when I submit the form it raises a "Routing Error" (No route matches [POST] "/tenants").
(I'm using Devise and Pundit)
I have a Property model having many Tenants models
class Property < ApplicationRecord
belongs_to :owner
has_many :tenants, dependent: :destroy
validates :address, presence: true
end
class Tenant < ApplicationRecord
belongs_to :user
belongs_to :property
has_many :incidents, dependent: :destroy
validates :first_name, presence: true
validates :last_name, presence: true
validates :email, presence: true, uniqueness: true
validates :phone, presence: true
validates :rental_price, presence: true
validates :start_date, presence: true
validates :rental_time, presence: true
end
Here are the routes:
Rails.application.routes.draw do
root to: 'pages#home'
devise_for :users
resources :agencies do
resources :owners, only: [:index, :new, :create]
end
resources :owners, only: [:show, :edit, :update, :destroy] do
resources :properties, only: [:new, :create]
end
resources :properties, only: [:index, :show, :edit, :update, :destroy] do
resources :tenants, only: [:new, :create]
end
resources :tenants, only: [:index, :show, :edit, :update, :destroy] do
resources :incidents, only: [:new, :create]
end
resources :incidents, only: [:index, :show, :edit, :update, :destroy]
resources :workers
the tenants controller:
class TenantsController < ApplicationController
before_action :set_tenant, only: [:show, :edit, :update, :destroy]
def create
#tenant = Tenant.new(tenant_params)
#tenant.user = User.create(email: #tenant.email, password: random_password, role: "tenant")
#tenant.property = Property.find(params[:property_id])
if #tenant.save
redirect_to :root
else
render :new
end
authorize(#tenant)
end
def new
#tenant = Tenant.new
#tenant.user = User.new
#tenant.property = Property.find(params[:property_id])
authorize(#tenant)
end
def show
authorize(#tenant)
end
def index
#tenants = policy_scope(Tenant).order(created_at: :desc)
end
def edit
authorize(#tenant)
end
def update
authorize(#tenant)
end
def destroy
authorize(#tenant)
#tenant.destroy
redirect_back(fallback_location: root_path)
end
private
def random_password
(('0'..'9').to_a + ('A'..'Z').to_a + ('a'..'z').to_a).shuffle.first(6).join
end
def set_tenant
#tenant = Tenant.find(params[:id])
end
def tenant_params
params.require(:tenant).permit(:first_name, :last_name, :email, :phone, :rental_price, :start_date, :rental_time)
end
end
the new.html.erb
<%= simple_form_for [#property, #tenant] do |f| %>
<%= f.input :first_name, label: false, placeholder: 'Prénom' %>
<%= f.input :last_name, label: false, placeholder: 'Nom' %>
<%= f.input :email, label: false, placeholder: 'Email' %>
<%= f.input :phone, label: false, placeholder: 'Téléphone' %>
<%= f.input :rental_price, label: false, placeholder: 'Montant du loyer en euros' %>
<%= f.input :start_date, placeholder: 'Date de début de location' %>
<%= f.input :rental_time, label: false, placeholder: 'Durée de location' %>
<%= f.submit " OK " %>
<% end %>
and the policies
class TenantPolicy < ApplicationPolicy
class Scope < Scope
def resolve
scope.all
end
end
def show?
admin? || (agency? && user.agency.tenants.include?(record)) || (tenant? && user.tenant == record)
end
def index?
admin? || (agency? && (record - user.agency.tenants).empty?)
end
def create?
admin? || (agency? && user.agency.properties.include?(record.property))
end
def update?
admin?
end
def destroy?
admin? || (agency? && user.agency.tenants.include?(record))
end
end
I would really like to understand why it doesnt work here as i made exactly the same thing for the property model (belonging to owner) and it worked.
Thanks!
Your error is occurring because you removed the :create action from your routes:
resources :tenants, only: [:index, :show, :edit, :update, :destroy] should include :create
I found what was wrong:
I forgot to instantiate #property in my controller methods.

NoMethodError in SubmittedQuizzes#index, why?

routes:
resources :users do
resources :submitted_quizzes, only: [:index, :create, :show]
end
submitted_quizzes/index.html.erb:
<% #submitted_quizzes.each do |quiz| %>
<ul>
<li> <%= quiz.name %> <span><%= link_to 'Show', quiz %></span></li>
</ul>
<% end %>
submitted_quizzes/show.html.erb:
<%= #submitted_quiz.name %>
SubmittedQuizzesController
def index
#user = current_user
#submitted_quizzes = #user.submitted_quizzes
end
def show
#submitted_quiz = current_user.submitted_quizzes.find(params[:id])
end
Why is this happening?
submitted_quiz.rb
class SubmittedQuiz < ActiveRecord::Base
belongs_to :user
belongs_to :quiz
has_many :submitted_answers, :dependent => :destroy
accepts_nested_attributes_for :submitted_answers, :reject_if => -> (a) {a[:content].blank? }, :allow_destroy => true
end
Just didn't read up on nested resources paths. The correct path should have been user_submitted_quiz_path(#user, submitted_quiz).

Rails create method failing

I'm trying to create "group posts" that are connected to a "user group" and a user. The first line of my create method is failing with this error:
Couldn't find UserGroup with 'id'=
I've been looking at blog building tutorials thinking that my "group post" is acting like a comment but instead of being attached to an article it's attached to a "user group".
I'm pretty new to Rails so it could be simply a syntax issue. Any advise would be appreciated.
Here is the group post create method:
def create
#user_group = UserGroup.find(params[:user_group_id])
#group_post = current_user.group_posts.new(group_post_params)
if #group_post.save
respond_to do |format|
format.html {redirect_to user_group_path(#user_group), notice: "Group Post created!"}
end
else
redirect_to user_group_path(#user_group), notice: "Something went wrong."
end
end
private
def group_post_params
params.require(:group_post).permit(:content, :post_type, :user_group_id)
end
Here is the user group model:
class UserGroup < ActiveRecord::Base
has_many :group_members, dependent: :destroy
has_many :members, through: :group_members, source: :user
has_many :group_posts, dependent: :destroy
validates :name, presence: true, length: {minimum: 5}
validates :searchable, presence: true, length: {minimum: 5}
def owners
members.includes(:group_members).where('group_members.owner = ?', true)
end
def regular_users
members.includes(:group_members).where('group_members.owner = ?', false)
end
end
Here is the group post model:
class GroupPost < ActiveRecord::Base
include PublicActivity::Model
belongs_to :user
belongs_to :user_group
validates :user_id, :presence => true
validates :content, :presence => true
end
And finally the routes:
Rails.application.routes.draw do
devise_for :users, controllers: {registrations: 'registrations'}
root 'pages#home'
resources :users, only: [:index, :show]
resources :friendships, only: [:create, :destroy, :accept] do
member do
put :accept
end
end
resources :posts, only: [:create, :edit, :update, :destroy]
resources :group_posts, only: [:create, :edit, :update, :destroy]
resources :activities, only: [:index] do
member do
put "upvote" =>"activities#upvote"
end
end
resources :user_groups do
resources :group_posts
resources :group_members
end
end
Here is the form partial submitting the group post:
<div class="posts-panel">
<%= form_for(#group_post) do |f| %>
<%= render 'partials/error_messages', object: f.object %>
<div class="form-group">
<%= f.text_area :content, placeholder: "Compose new post...", class: "form-control" %>
</div>
<div class="form-group">
<%= f.select :post_type, [['Request', 'request'],['Report', 'report']], {}, {class: "form-control"} %>
</div>
<div class="form-group">
<%= hidden_field_tag :user_group_id, #usergroup.id %>
<%= f.submit "Post", class: "btn btn-primary" %>
</div>
<% end %>
</div>
Complete Params:
{"utf8"=>"✓", "authenticity_token"=>"thkRQYNcl+ySSoWIE83V22DEqYdttg+TF4coFsmasXkt2mylgB2YG/vAl2KYRey/djTqL5iNSTIyWJpsSWyCQQ==", "group_post"=>{"content"=>"This is it", "post_type"=>"prayer"}, "user_group_id"=>"1", "commit"=>"Post", "controller"=>"group_posts", "action"=>"create"}
The user_group_id was not inside the params hash. Adding the following line to the create method solved the issue:
#group_post.user_group = #user_group

Resources