Many to Many AND habtm-checkboxes help needed! - ruby

For some reason nothing is getting stored in my groups_user table below is the info.
My Models
group.rb
class Group < ActiveRecord::Base
has_and_belongs_to_many :users
end
user.rb
class User < ActiveRecord::Base
has_and_belongs_to_many :groups
end
groups_user.rb
class GroupsUser < ActiveRecord::Base
end
The Entity Relationship Diagram
http://i.imgur.com/MqWok.png
The Form
http://i.imgur.com/BwwaV.png
The view code
<% for group in #groups %>
<%= check_box_tag "user[group_ids][]", group.id, #user.groups.include?(group) %>
<%= group.description %>
<% end %>
users_controller.rb
def update
#user = User.find(params[:id])
params[:user][:group_ids] ||= []
if #user.update_attributes(params[:user]) flash[:success] = "User updated."
redirect_to #user #end
else
#title = "Edit user"
render 'edit'
end
end

i had the same problem and it take my head blowing off:
The solution for me was simply adding this into my User Model (app/models/user.rb)
class User < ActiveRecord::Base
attr_accessible :group_ids
[...]
end
Hope this helps!

it should be groups_users not groups_user and you don't have to create model for this table

Related

has_many and belongs_ association rails 4

I am while leraning how to use association in rails 4 application
I have a user having many opinions and I want to add user opinion in the book show page
This is how i proceed:
my user.rb
class User < ActiveRecord::Base
has_one :panier
has_many :opinions
end
opinion.rb
class Opinion < ActiveRecord::Base
belongs_to :user
end
views/books/show.html.erb
<h2>Votre opinion nous intéresse:</h2>
<%= form_for([#user, #user.opinions.build]) do |f| %>
<p>
<%= f.label :body, 'votre opinion' %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
opinion_controller.rb
class OpinionsController < ApplicationController
def create
#user = current_user
#opinion= #user.opinion.create(opinion_params)
end
private
def opinion_params
params.require(:opinion).permit(:body)
end
end
and in books_controllers this is my show method:
def show
#user= current_user
#books= Book.all
end
my routes:
get 'books/show' => 'books#show' , as: :books_list
resources :users do
resources :opinions
end
what I got as error:
undefined method `opinions' for nil:NilClass
in this line of code:
Most probably #user.opinions in your form causing this issue. check whether current_user returning object or not.
Also in your create method there is typo(#user.opinion), it should be #user.opinions.
Use accept nested attributes for same.

Edit a Parent Class from a Child Form

Currently, I am able to create multiple Students through my Adult Form by using accepts_nested_attributes_for :student.
But how can I Edit an existing Adult through a Student Form? (So the Opposite, except Edit)
Currently I am able to create more Parents through my Student form, but thats not what I want.
MODELS
class Adult < ActiveRecord::Base
has_many :students
accepts_nested_attributes_for :student
end
class Student < ActiveRecord::Base
belongs_to :adult
accepts_nested_attributes_for :adult
end
CONTROLLER
class StudentsController < ApplicationController
def update
#adult = Adult.find(params[:adult_id])
#student = Student.find(params[:id])
if #student.update_attributes(student_params)
redirect_to path
end
end
private
def student_params
params.require(:student).permit(:adult_id, :school_id, :username, :password,
:firstName, :middleName, :lastName, :alias,
adult_attributes: [:id, :name])
end
end
VIEWS
###HOW CAN I UPDATE THE EXISTING PARENT AS OPPOSE TO CREATING ONE
<%= simple_form_for #student.build_adult do |f| %>
<h4>Update Parent Information</h4>
<%= f.label :firstName, 'First Name' %>
<%= f.text_field :firstName, placeholder: "Parent's First Name", :class => "form-control"%>
<%= f.submit "Save & Continue", class: "btn btn-primary"%>
<% end %>
ROUTES
resources :adult do
resources :student
end
Firstly,it is has_many :students,so it should be accepts_nested_attributes_for :students not accepts_nested_attributes_for :student.
Secondly,if i understood your question correctly,you are trying to update the existing parent(adult) record but you are ending up creating a new one.Is that the problem? If so,you need to permit the :id of the student for which the parent(adult) record need to be updated.
Change your student_params method to like this
def student_params
params.require(:student).permit(:id,:adult_id, :school_id, :username, :password,
:firstName, :middleName, :lastName,:alias,adult_attributes: [:id, :name])
end
I'm not sure about this solution, but it may work...
Try using #parent.update_attributes instead of creating a separate parent form, send the parent params with the student params. You may need to define a parent_params() function to permit them.
** I believe the permit params will filter out the non-permitted ones, so you won't need to specify only the student or parents fields for their respect update_attributes.

How to save to Database with associations in rails protecting mass assignment

After trying for few hours I can not save to the database.
The context is this:
I have two types of users, one for that I only need very basic information [Username, email, password] and another kind of user for who I need a lot of information [age, gender, city and so on]
I did not use STI becouse of the vast quantity of Null values there would be in the table.
So I created this three modes in which a user has a profile (profiles table) or not depending of its type [1 or 2], and a field of this profile is the city this user is living in, that relates to another table in the DB, the cities table
class User < ActiveRecord::Base
has_one :profile
has_one :city, through: :profile
end
class Profile < ActiveRecord::Base
belongs_to :user
belongs_to :city
[...a bunch of fields here]
end
class City < ActiveRecord::Base
has_many :profiles
has_many :users, through: :profiles
end
When I play with them in the rails console everything goes OK:
usr = User.new(name: "roxy", email: "roxy#example.me", password: "roxanna", password_confirmation: "roxanna", utype: 1)
cty = City.new(name: "Bucaramanga")
prf = Profile.new (rname: "Rosa Juliana Diaz del Castillo"...)
prf.city = cty
usr.profile = prf
usr.valid?
=> true
usr.save
=> true
but when I try to save in the app (View an Model)
<%= f.label :city, "En que ciudad te encuentras?"%>
<%= select_tag :city, options_from_collection_for_select(City.all, 'id', "name"),{:prompt => 'Selecciona tu ciudad'}%>
def new
#profile = Profile.new
end
def create
#profile = params[:profile]
#city= City.find_by_id(params[:city].to_i)
#profile.city = #city
end
I get this error:
undefined method `city=' for #<ActiveSupport::HashWithIndifferentAccess:0xa556fe0>
Can someone please help me?
UPDATE
As David suggested I created the Profile object in the first line of the create method, so my controller now look like this:
def create
#profile = Profile.new(params[:profile])
#city= City.find_by_id(params[:city].to_i)
#profile.city = #city
#usr = current_user
if #usr.profile.exists? #profile
#usr.errors.add(:profile, "is already assigned to this user") # or something to that effect
render :new
else
#usr.profile << #profile
redirect_to root_path
end
end
But I'm getting this error now
undefined method `exists?' for nil:NilClass
current_user returns the #current_user
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
Could you tell me please, what am I doing wrong?
I want to write this to all of you who are beginning as well as I am and are stuck in this step.
I had to create a new project and play with it to realize what I was doing wrong. I figured out that I was validating a last time field I added to the Profiles table and had
# education :string(255) not null
but I had not added it yet to the form so the error launched is:
Failed to save the new associated so_profile.
Now, you know if you got this error, go check your schema and look for NOT_NULL fields you might be missing in the form, also you can comment out all your model validations and after it's working uncomment'em to be sure.
So, my Final Models:
class User < ActiveRecord::Base
has_one :profile
has_one :city, through: :profile
attr_accessible :email, :name
end
class Profile < ActiveRecord::Base
belongs_to :user
belongs_to :city
attr_accessible :age, :fcolor, :gender
end
class City < ActiveRecord::Base
has_many :profiles
has_many :users, through: :profiles
attr_accessible :name
end
My controllers:
class ProfilesController < ApplicationController
def new
#user = User.find_by_id(params[:id])
#profile = Profile.new
end
def create
#profile = Profile.new(params[:profile])
city = City.find_by_id(params[:city])
#profile.city = city
#user = User.find_by_id(params[:userid])
#user.profile = #profile
if #user.save
flash[:success] = "Guardado"
redirect_to profile_path(id: #user.id)
end
end
def show
#user = User.find(params[:id])
end
end
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
flash[:success] = "Registrado!"
redirect_to new_profile_path(id: #user.id)
else
flash[:error] = "No Registrado :("
redirect_to new
end
end
def show
#user = User.find_by_id(params[:id])
end
end
In a real app you have to use Cookies or something else to keep the session alive and therefore the user_token from where you get the user_id, but it works to play with associations.
The views:
profiles/new.html.erb
<%= #user.name %>
<%= form_for #profile, url: {action: :create, userid: #user.id } do |f| %>
<%= f.label :age, "Edad" %>
<%= f.text_field :age%> <br />
<%= label :city, "Ciudad"%>
<%= select_tag :city, options_from_collection_for_select(City.all, 'id', 'name')%>
<%= f.submit %>
<% end %>
profiles/show.html.erb
Hello <%= #user.name %><br />
Tu edad es: <%= #user.profile.age %><br />
Vives en <%= #user.profile.city.name%>
users/new.html.erb
<%= form_for #user do |f|%>
<%= f.label :name, "Nombre"%>
<%= f.text_field :name, size: 20, placeholder: "Escribe tu nombre aqui" %><br />
<%= f.label :email, "Email"%>
<%= f.text_field :email, size: 20, placeholder: "Escribe tu email aqui" %><br />
<%= f.submit "Sign me up!"%>
users/show.html.erb
Name: <%= #user.name %><br />
Email: <%= #user.email %>
And that's it!
Cheers.
Learn to read the error messages. The problem is that #profile is a hash because you didnt't actually create a new Profile object on the first line of the create method.
I think that the correct is
#so_profile.City
not
#so_profile.city
Because the class name is City

has_many through form driven by checkboxes

Models : based on rails 3 guide!
class Physician < ActiveRecord::Base
has_many :physician_specialities
has_many :specialities, :through => :physician_specialities
end
class speciality < ActiveRecord::Base
has_many :physician_specialities
has_many :physicians, :through => :physician_specialities
end
class PhycianSpeciality < ActiveRecord::Base
belongs_to :physician
belongs_to :patient
end
And the database schema looks like this :
Physician
id
name
Speciality
id
name
PhycianSpeciality
id
physician_id
speciality_id
description
I want to have a form which is able to add specialities to a physician and write a small description of this speciality (according to the physician).
I think i can use somethings like this Quick Tip: has_many :through => checkboxes!
<% form_for #physician do -%>
<% Speciality.all.each do |group| -%>
<div>
<%= check_box_tag :speciality_ids, speciality.id, #user.specialities.include?(speciality), :name => 'user[speciality_ids][]' -%>
<%= label_tag :speciality_ids, speciality.name -%>
</div>
<% end -%>
<%= submit_tag -%>
<% end -%>
But i don't know where can i put the speciality description ...
It looks to me like you are missing at least two relationship tables/models.
SpecialtyDescription
PhysicianSpecialityDescription
That way you can have the right connection between PhysicianSpeciality & PhysicianSpecialityDescription (PhysicianSpeciality_id, SpecialtyDescription_id) & SpecialtyDescription.
Since the description is pending the creation of the join record in PhysicianSpecialty, I would just pass the description in as a text_area and sort it out pending the save of the Physician.
physicians_controller.rb
# i imagine ur update method would look kinda like this
def update
#physician = Physician.find(params[:id])
if #physician.update_attributes(params[:physician])
physician_specialty = PhysicianSpecialty.find_by_specialty_id(:specialty_id => specialty.id)
physician_specialty.update_attribute(:description, params[:description])
else
render :action => :edit
end
end

Rails accept_nested_attributes is not functioning

class Invoice < ActiveRecord::Base
attr_accessible :line_items_attributes
accepts_nested_attributes_for :line_items
has_many :line_items
end
class LineItem < ActiveRecord::Base
belongs_to :invoice
def prepopulate_with(l_items)
unless l_items.empty?
self.line_items = l_items
end
end
end
class InvoiceController < ApplicationController
def new
#invoice = Invoice.new
if params[:line_items]
line_items = params[:line_items].map{|li| LineItem.find(li)}
#prepopulate_with just set #invoice.line_items = whatever_array_of_line_items that was passed in
#invoice.prepopulate_with(line_items)
end
end
def create
#invoice = Invoice.new(params[:invoice])
if #invoice.save
flash[:notice] = "Successfully created invoice."
redirect_to #invoice
else
render :action => 'new'
end
end
end
Line Item gets created prior to invoice. So they will have their individual IDs. I basically preload Invoice.new with line_items on new action. That nested form of invoice which contains line_items (with id) then gets posted to the create action.
Error:
ActiveRecord::RecordNotFound in InvoicesController#create
Couldn't find LineItem with ID=21 for Invoice with ID=
I've included the relevant section of the form below:
<% f.fields_for :line_items do |li| %>
<%= li.text_field :description %>
<%= li.text_field :amount %>
<% end %>

Resources