Rails Nested Form Attributes Building - ruby-on-rails

I'm having real difficulty understanding how to go about a nested form that I have. A user would sign into the application, click 'create a team' and this page would allow users to enter a team name and a list of members for the team. (effectively creating a team member list).
I have a nested form which contains fields_for memberships so as to create the membership. See screenshot of form
When the form is saved, the membership model runs Entrant.find_or_creates_by_name to create the entrant.
The problem I'm having is that on the creation I get the error messages:
Memberships team can't be blank
How do I prevent this from happening and allow users to add entrants / ensure the membership is created correctly?
Apologies if this has already been answered, (there seems to be many topics on has_many through with nested resources, but none that I could find dealt with my specific issue (I could / seemed to be unclear)
My create action is currently the standard nested form action as follows:
def create
#user = current_user
#team = #user.teams.build(params[:team])
if #team.save
redirect_to(team_url(#team), :notice => "Team was successfully saved")
else
render :action => "new"
end
end
I have the following models:
User Model
class User < ActiveRecord::Base
has_many :teams
end
Team Model
class Team < ActiveRecord::Base
belongs_to :user
has_many :memberships
has_many :entrants, :through => :memberships
attr_accessible :name, :team_type, :website, :memberships_attributes
accepts_nested_attributes_for :memberships, allow_destroy: true
end
Memberships Model
class Membership < ActiveRecord::Base
belongs_to :team
belongs_to :entrant
validates :team_id, presence: true
validates :entrant_id, presence: true
attr_accessor :entrant_name
attr_accessible :entrant_name
def entrant_name
entrant && entrant.name
end
def entrant_name=(name)
self.entrant = Entrant.find_or_create_by_name(name) unless name.blank?
end
end
Entrants Model - This is effectively a member of the team for memberlistings however when a user enters a team they can specify nickname which may change across teams.
class Entrant < ActiveRecord::Base
attr_accessible :name
has_many :memberships
has_many :teams, :through => :memberships
end

I think its a validation error. Try to remove
validates :entrant_id, presence: true
From membership model.

Related

RailsActive Record and Nested Resources

I would like for click action on a button to result in the addition of a resource to a join table. There are several ways to do this in the console but I can't for the life of me figure out how to implement this outside the console.
Here is an example that mimics my current model:
class Student < ActiveRecord::Base
has_many :reports
has_many :schools, through: :reports
end
class School < ActiveRecord::Base
has_many :reports
has_many :students, through: :reports
accepts_nested_attributes_for :reports
end
class Report < ActiveRecord::Base
belongs_to :student
belongs_to :school
accepts_nested_attributes_for :student
accepts_nested_attributes_for :school
validates :student_id, presence: true
validates :school_id, presence: true
end
This method returns all the report cards that belong to a student (student already exists in
my database):
#student.reports
This method returns all the schools that a student has attended:
#student.schools
I can add/associate an existing school to a student by doing this:
#school = School.find(params[:id])
if student.present?
#student = Student.find(params[:id])
#student.schools << #school
Please note that the association of a single report to many students is intentional. My question now is how do I enable a student to add a school to their report simply by clicking on a particualr school? My reports table (which basically is a join table) should be automatically updated as soon as this click_action takes place/happens (that is a new row that associates that particular student_id with that particular school id should be created).
Been trying to figure it out but not making progress for some reason. Thank you in advance!
Well, to start with, in your view you should have a javascript/DOM event for each school:
onclick(window.location.href = "<%= path_to_add_school_to_students(student,school) %>")
So there you have your one click.
In your controller
student=Student.find(params[:student])
if student.schools.find(params[:school]).nil? # if school not already assigned
student.reports.create(:school_id => params[:school])
end

Rails admin hide belongs_to field in has_many nested form

I have two Models
class Entity < ActiveRecord::Base
# Associations
has_many :contacts
accepts_nested_attributes_for :contacts, :allow_destroy => true
end
class Contact < ActiveRecord::Base
# Associations
belongs_to :entity
end
Now in rails admin I am getting below options.
Add new Contact Form
Add new Entity Form
I need to hide Entity field in contact form , while adding new entity.
Any help will be useful.
You can automatically hide the fields using inverse_of like this
class Entity < ActiveRecord::Base
# Associations
has_many :contacts, inverse_of: :entity
accepts_nested_attributes_for :contacts, allow_destroy: true
end
class Contact < ActiveRecord::Base
# Associations
belongs_to :entity, inverse_of: :contacts
end
If you set the :inverse_of option on your relations, RailsAdmin will
automatically populate the inverse relationship in the modal creation
window. (link next to :belongs_to and :has_many multi-select widgets)
Source: https://github.com/sferik/rails_admin/wiki/Associations-basics
Let me know how it went
For the sake of completness and because i had this problem too and solved it, if you want to you can configure a model when it is used inside a nested form just like you do with edit, update, create and nested
class Contact < ActiveRecord::Base
# Associations
belongs_to :entity
rails_admin do
nested do
configure :entity do
hide
end
end
end
end
Visit the official wiki for more info

Rails multiple has_many :through and displaying associations

I'm building an application where a user can build a lesson from an assortment of standards and questions to teach the standards, but I'm not exactly sure if I have set up everything correctly or not.
The 'new' page allows the user to use drop down menus to sort through to select the standards through the Lesson Controller
def new
#search = Standard.search(params[:q])
#standards = #search.result
#lesson = Lesson.new
end
def create
#lesson = current_user.selects.build(params[:lesson])
if #lesson.save
redirect_to edit_lesson_path(#lesson)
else
render :action => 'new'
end
end
def edit
#lesson = Lesson.find(params[:id])
#standards = #lesson.standards
end
Once the standards are selected, the user is redirected to the 'edit' page which shows each of the selected standards, but this is the part where I'm having trouble with and I'm not sure my models are set up correctly. There is a has_many through relationship between lessons and standards to select standards, and also a has_many through relationship between lessons and questions as well to select the questions associated with each standard.
I'm trying to list each of the questions associated with the standards underneath the parent standard, I have tried #questions = #standards.questions in the 'edit' method, but an ActiveRecord Relation NoMethod error is called. I have also tried #questions = Question.where(:standard_id => #standards) in the controller, but the page lists all of the questions for all of the selected standards underneath each standard.
My lesson model:
class Lesson < ActiveRecord::Base
attr_accessible :user_id, :name, :grade_id, :text_id, :date, :subject_id, :question_ids
has_many :select_standards
has_many :standards, through: :select_standards
has_many :select_questions
has_many :questions, through: :select_questions
end
Standard model:
class Standard < ActiveRecord::Base
attr_accessible :content, :grade_id, :subject_id
belongs_to :subject
belongs_to :grade
has_many :questions
end
Question model:
class Question < ActiveRecord::Base
attr_accessible :content, :standard_id
belongs_to :standard
has_many :select_questions
has_many :lessons, through: :select_questions
end
Select_standards:
class Selection < ActiveRecord::Base
attr_accessible :lesson_id, :standard_id
belongs_to :lesson
belongs_to :standard
end
The problem seems to be related to Rails not being able to figure out proper class names for your association names. For example, you've specified has_many :select_standards for your class Selection, by default Rails would search for SelectStandard class for association name :select_standards. The fix is easy in this case, which is to either change the association declaration to:
has_many :selections
or add class_name to association as:
has_many :select_standards, class_name: 'Selection'
You need to make sure that this is done for any and all the custom association names that do not match the actual ActiveRecord inherited class names.

ActiveRecord won't build the right class using STI

I'm using single table inheritance in my application and running into problems building inherited users from an ancestor. For instance, with the following setup:
class School < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
attr_accessible :type #etc...
belongs_to :school
end
Class Instructor < User
attr_accessible :terms_of_service
validates :terms_of_service, :acceptance => true
end
Class Student < User
end
How can I build either a instructor or student record from an instance of School? Attempting something like School.first.instructors.build(....) gives me a new User instance only and I won't have access to instructor specific fields such as terms_of_service causing errors later down the rode when generating instructor-specific forms, building from console will give me an mass-assignment error (as it's trying to create a User record rather than an Instructor record as specified). I gave the example of School, but there are a few other associations that I would like to inherit from the User table so I don't have to repeat code or fields in the database. Am I having this problem because associations can not be shared in an STI setup?
You should specify instructors explicitly
class School < ActiveRecord::Base
has_many :users
has_many :instructors,:class_name => 'Instructor', :foreign_key => 'user_id'
end
And what else:
class School < ActiveRecord::Base
has_many :users
has_many :instructors
end
class Instructor < User
attr_accessible :terms_of_service # let it be at the first place. :)
validates :terms_of_service, :acceptance => true
end
OK it seems part of the problem stemmed from having the old users association inside of my School model. Removing that and adding the associations for students and instructors individually worked.
Updated School.rb:
class School < ActiveRecord::Base
#removed:
#has_many :users this line was causing problems
#added
has_many :instructors
has_many :students
end

Getting values through relational table

In my app I have a page which render all the projects in the database. What I want is to be able to filter the results, for example by showing only the once in which the user is a member.
Below is from my projects controller, where I want to do exactly that (show only projects where the user is a member). What do is to first get all the projects from 'ProjectUser' where the user_id is found. Then I want to use this array to retrieve all the relevant projects from the table 'Projects', with the use of #user_is_member.project_id.
This does not work because it only give me ONE project, not all.
How can I change the code so I accomplish what I want?
The code:
#user_is_member = ProjectsUser.where(:user_id => current_user.id)
#user_is_member.each do |member|
#projects = Project.where(:id => member.project_id)
end
Tables:
projects_users:
project_id
user_id
projects:
id
...non relevant fields...
Models:
User model:
class User < ActiveRecord::Base
has_many :project_users
has_and_belongs_to_many :projects
end
Project model:
class Project < ActiveRecord::Base
has_and_belongs_to_many :users # => , :class_name => 'User'
belongs_to :user
end
ProjectUser model:
class ProjectsUser < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
Note: current_user is the currently logged in user (which has access to all the user fields, e.g "id")
This is not a good way to associate the models. If you want to associate user to project and make one user to admin/creator then you should associate your models as:
User
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :password
has_secure_password
has_many :projects_users
has_many :projects, :through => :projects_users
end
Project
class Project < ActiveRecord::Base
has_many :projects_users
has_many :users, :through => :projects_users
end
ProjectsUser
class ProjectsUser < ActiveRecord::Base
attr_accessible :role
belongs_to :user
belongs_to :project
end
I have added an extra column/attribute to your ProjectsUser Model that will have a string value (admin/member). And now you can get the members for a project by doing #project.users.where(:role => 'member') and admin by #project.users.where(:role => 'admin').first.
If you don't want to change your way then in your controller do something like:
#user_is_member = ProjectsUser.where(:user_id => current_user.id)
project_ids = []
#user_is_member.each do |member|
project_ids << member.project_id
end
#projects = Project.where(:id => project_ids)
If you want all the projects for the current_user, you can just do:
#projects = current_user.projects
I am assuming you have something like:
class User < ActiveRecord::Base
has_many :project_users
has_many :projects, :through => :project_users
end
class ProjectUser < ActiveRecord::Base
belongs_to :user
belongs_to :project
end
class Project < ActiveRecord::Base
has_many :project_users
has_many :users, :through => :project_users
end
The problem is that you have no project_id for some user which is somehow deleted.
Check your database that which project_id is nil by putting puts like statements in a loop.
Alternatively, you can use :dependent => :destroy on your relationship to get rid of such inconsistent data. It usually happens while you are testing and somehow delete any record but forget to delete the foreign key association relation for other table.
This can be accomplished like following:
#user_is_member = ProjectsUser.where(:user_id => current_user.id)
#user_is_member.each do |member|
puts "Checking the project id existence for each user member"+member.project_id.to_s
end

Resources