Nested resource #index action not working as expected - ruby-on-rails

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

Related

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.

Rails 5 - has_many through: association and select in view

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

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

Polymorphic Commenting

I'm currently developing an app which allows users to post from their own account, but if they're an administrator of a group or venue, they can also post as that entity. I'm struggling converting the polymorphic association ideas from some of the other questions out there as generally they're all based around being able to comment on multiple things and not from multiple things.
I think my main issue is that I have my user's post form on the homepage, so it does not have an ID in the URL.
My post controller looks like this:
class PostsController < ApplicationController
before_action :authenticate_user!, only: [:create, :destroy]
before_filter :load_postable
def index
end
def new
#post = Postabe.posts.new(post_params)
end
def create
#post = #postable.posts.build(post_params)
if #post.save
flash[:success] = "Post created!"
redirect_to root_url
else
#feed_items = []
render 'static_pages/home'
end
end
def destroy
#post.destroy
redirect_to root_url
end
private
def post_params
params.require(:post).permit(:content)
end
def load_postable
resource, id = request.path.split('/')[1, 2]
resource_name = resource.singularize.classify
if resource_name == "User"
#postable = current_user
else
#postable = resource_name.constantize.find(id)
end
end
end
and my _post_form.html.erb partial:
<%= form_for ([#postable, #postable.post.new]), remote: true do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Create a Post..." %>
</div>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
my related routes:
devise_for :users, :controllers => { :omniauth_callbacks => "omniauth_callbacks", :registrations => "registrations" }
resources :users, :only => [:index] do
member do
get :favourite_users, :favourited_users
end
resources :posts
end
resources :venues do
resources :posts
end
resources :groups do
resources :posts
end
Models as follows:
class Post < ActiveRecord::Base
belongs_to :postable, polymorphic: true
end
class User < ActiveRecord::Base
has_many :posts, as: :postable, dependent: :destroy
end
class Venue < ActiveRecord::Base
has_many :posts, as: :postable, dependent: :destroy
end
class Group < ActiveRecord::Base
has_many :posts, as: :postable, dependent: :destroy
end
It seems that I keep getting the error
Couldn't find Post without an ID
but I don't know why it's looking for a Post ID if it's not been created yet. Any help would be appreciated!
You have before_filter :load_postable in your controller. By default it will run for all the actions in your controller, even when the id is not specified. The error is thrown by #postable = resource_name.constantize.find(id), id is nil for index method.
Change this line to:
before_filter :load_postable, except: [:index]

undefined method `discussion_postcomments_path' for #<#<Class:0x7a1c360>:0x7a20c38>

I recently added a new Model (discussion.rb) and Controller (discussions_controller.rb). I am trying to get postcomments to work with discussions.
discussion.rb
class Discussion < ActiveRecord::Base
belongs_to :user
has_many :postcomments, dependent: :destroy
validates :user_id, presence: true
validates :content, presence: true
attr_accessible :content, :user_id
default_scope order: 'discussions.created_at DESC'
end
Here's what I have in routes
resources :discussions, :path => "disc"
resources :users do
member do
get :following, :followers
end
end
resources :sessions, only: [:new, :create, :destroy]
resources :microposts, only: [:create, :destroy]
resources :discussions, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
resources :microposts do
resources :postcomments
resources :discussions do
resources :postcomments
end
end
here's the postcomments model
class Postcomment < ActiveRecord::Base
attr_accessible :comment_content
belongs_to :user
belongs_to :micropost
belongs_to :discussion
validates :comment_content, presence: true
validates :user_id, presence: true
default_scope order: 'postcomments.created_at ASC'
end
I'm trying to use this in view except, I get the error posted in the title
<%= form_for([discussion, #comment]) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_field :comment_content %>
</div>
<div class="ItemContainer">
<div class="ItemInput">
<button class="btn" type="submit">
Comment
</button>
</div><div class="ItemCommentCount">
<% end %>
It says that the error is caused from this line
<%= form_for([discussion, #comment]) do |f| %>
Anyone know how I can fix this path problem?
class PostcommentsController < ApplicationController
def create
#micropost = Micropost.find(params[:micropost_id])
#comment = Postcomment.new(params[:postcomment])
#comment.micropost = #micropost
#comment.user = current_user
if #comment.save
redirect_to(:back)
else
render partial: 'shared/_postcomment_form', locals: { micropost: #micropost }
end
end
def createdisc
#discussion = Discussion.find(params[:discussion_id])
#comment = Postcomment.new(params[:postcomment])
#comment.discussion = #discussion
#comment.user = current_user
if #comment.save
redirect_to(:back)
else
render partial: 'shared/_postcomment_form', locals: { discussion: #discussion}
end
end
end
Try consolidating your use of resources :discussions in your routes file. I've edited below assuming you didn't intend to nest discussions under microposts.
resources :discussions, only: [:create, :destroy], path: "disc" do
resources :postcomments
end
resources :users do
member do
get :following, :followers
end
end
resources :sessions, only: [:new, :create, :destroy]
resources :microposts, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
resources :microposts do
resources :postcomments
end
This line
<%= form_for([discussion, #comment]) do |f| %>
This discussion should be an instance variable as well:
<%= form_for([#discussion, #comment]) do |f| %>
Then you need to define #discussion in the controller

Resources