Rails: undefined method 'MODELNAME' ? Am I saving the wrong thing on create? - ruby-on-rails

Currently I'm making an app for users to create picture albums. The catch is that there can be multiple owners for each album, so in the form to create an album there is a check box portion where you highlight your friends names and "invite them" to be an owner. However, I am having a hard time getting it to work since it's giving me an error in my AlbumsController#create. The error is :
undefined method 'user' for #<Album:0x007fcd9021dd00>
app/controllers/albums_controller.rb:43:in 'create'
Here's my form
<%= form_for ([#user, #album]), :html => { :id => "uploadform" } do |f| %>
<div class="formholder">
<%= f.label :name %>
<%= f.text_field :name %>
<br>
<label>Hosts</label>
<% #user.friends.each do |friend| %>
<%= friend.name %>
<%= check_box_tag 'album[user_ids][]', friend.id, #album.users.include?(friend) %>
<% end %>
<%= f.label :description %>
<%= f.text_area :description %>
<br>
<%=f.submit %>
</div>
<% end %>
The checkboxes return an array of friend.id values that I want to invite to be owners for the album. The tricky part here is that I have a imaginary pending_album column in my join album_user model. Here's what is sending me errors that I can't figure out how to fix:
albums controller
def create
#user = User.find(params[:user_id])
#album = #user.albums.build(params[:album], :status => 'accepted')
#friends = #user.friends.find(params[:album][:user_ids])
for friend in #friends
params[:album1] = {:user_id => friend.id, :album_id => #album.id, :status => 'pending'}
AlbumUser.create(params[:album1])
end
#the next line is where the error occurs. why???
if #user.save
redirect_to user_album_path(#user, #album), notice: 'Album was successfully created.'
else
render action: "new"
end
end
album model
class Album < ActiveRecord::Base
attr_accessible :name, :description, :user_ids
validates_presence_of :name
validates :user, :uniqueness => true
has_many :album_users
has_many :users, :through => :album_users
has_many :photos
end
user model
class User < ActiveRecord::Base
has_secure_password
attr_accessible :email, :name, :password, :password_confirmation, :profilepic
validates_presence_of :password, :on => :create
validates_format_of :name, :with => /[A-Za-z]+/, :on => :create
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
validates_length_of :password, :minimum => 5, :on => :create
# validates :album, :uniqueness => true
has_many :album_users
has_many :albums, :through => :album_users, :conditions => "status = 'accepted'"
has_many :pending_albums, :through => :album_users, :source => :album, :conditions => "status = 'pending'"
accepts_nested_attributes_for :albums
has_many :friendships, :dependent => :destroy
has_many :friends, :through => :friendships, :conditions => "status = 'accepted'"
has_many :requested_friends, :through => :friendships, :source => :friend, :conditions => "status = 'requested'", :order => :created_at
has_many :pending_friends, :through => :friendships, :source => :friend, :conditions => "status = 'pending'", :order => :created_at
has_attached_file :profilepic
before_save { |user| user.email = email.downcase }
def name_with_initial
"#{name}"
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
album_user join table model
class AlbumUser < ActiveRecord::Base
attr_accessible :user_ids, :album_id, :status, :user_id
belongs_to :album
belongs_to :user
end
parameters (looks a little fishy... especially since album_id is nil):
{"utf8"=>"✓",
"authenticity_token"=>"xkIi6+1vjEk4yQcFs9vI1uvI29+Gyuenyp71vhpX9Hw=",
"album"=>{"name"=>"123123",
"user_ids"=>["27",
"28"],
"description"=>"123123"},
"commit"=>"Create Album",
"user_id"=>"29",
"album1"=>{"user_id"=>28,
"album_id"=>nil,
"status"=>"pending"}}
I'm not too sure what I'm doing wrong. Can someone help please!!

The error message is:
undefined method 'user' for #<Album:0x007fcd9021dd00>
All right, so something's calling Album#user. Line 46 in the controller is #user.save, so how is user getting called?
class Album < ActiveRecord::Base
attr_accessible :name, :description, :user_ids
validates_presence_of :name
validates :user, :uniqueness => true # <-- bam!
has_many :album_users
has_many :users, :through => :album_users
has_many :photos
end
save triggers validations, including that line right there, which validates that user is unique. Since this is exploding, I'm guessing that user is a column that doesn't exist, either because a) it's not defined in a migration or b) you didn't run the migration.
(As an aside, I'm rather confused as to why you would have a unique user attribute on Album, an AlbumUser model with both user_id and user_ids, and a User model. Maybe it makes sense, but I think it's more likely that it all needs a cleanup.)

Your album really has many several users? Then that should return method "user"? If want that one user owned album you must use belongs_to in your model. Then method "user" will return correct user to album

Related

Issue occurs due to "accepts_nested_attributes_for" and "has_many through" relationship which gives not id found error with factory_girl and rspec

Following are models:
class User < ActiveRecord::Base
has_many :companies_users
has_many :companies, :through => :companies_users
end
class Company < ActiveRecord::Base
has_many :companies_users
has_many :users, :through => :companies_users
accepts_nested_attributes_for :users
attr_accessible :name, :address_1, :address_2, :area, :city, :state, :zipcode, :country, :users_attributes
after_create :create_subscriptions
def create_subscriptions
subscription=Subscription.create(:company_id => self.id, :subscription_dt => Date.today, :is_active => 'Y', :user_id => self.users.first.id)
subscription.save
end
end
class CompaniesUser < ActiveRecord::Base
belongs_to :user
belongs_to :company
end
Following are spec/factories/factory.rb
FactoryGirl.define do
factory :company do |f|
f.name "TestCompany"
f.domain_url "test_url"
users {|t| [t.association(:user)] }
end
factory :user do |f|
f.first_name "John"
f.last_name "Doe"
f.password "password"
f.email "JohnDoe#test.com"
f.mobile_no "25589875"
f.fax_no "25548789"
f.office_no "25578455"
end
factory :companiesuser do |f|
association :user
association :company
end
end
Following is my spec/model/company_spec.rb
context "Check methods" do
it "check after create methods" do
company = FactoryGirl.create(:company)
end
end
While executing above company_spec it creates an issue due to method subscription which exist in company model and call after create callback create_subscriptions.which require self.users.first.id which it did not get and provide me following error.
$ rspec spec/models/company_spec.rb
F
Failures:
1) Company Model: Check methods check after create methods
Failure/Error: company = FactoryGirl.create(:company)
RuntimeError:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
# ./app/models/company.rb:47:in `create_subscriptions'
# ./spec/models/company_spec.rb:45:in `block (3 levels) in <top (required)>'
Can anyone let me know what i need to do or its any association related issue? it create problem because first it enter values in company but not able to enter value in users table so not get user id which required in subscription method.
I resolved above issue by change code in "spec/model/company_spec.rb" as follow:
context "Check methods" do
it "check after create methods" do
company = create(:company,"name"=>"mycom","domain_url"=>"test","users_attributes"=>{"0"=>{"email"=>"test#testing.com","password"=>"password","password_confirmation"=>"password"}})
end
end
It created data in my join table also and worked successfully. Obviously its not done by factory join. I directly pass the user attributes here. So removed line
users {|t| [t.association(:user)] }
from company's factory.
I've done a nested has_many :through and you have to basically pass the attributes to the :companies_users model and then to the :users model
My Code (Rails 4.0)
Form
#views/admin/posts/new
<%= form_for [:admin, resource], :html => { :multipart => true } do |f| %>
<table class="resource_table">
<thead>
<th colspan="2"><%= params[:action].capitalize %> <%= resource_class %></th>
</thead>
<tbody class="form">
<% attributes.each do |attr| %>
<tr class="<%= cycle('odd', '')%>">
<td><%= resource_class.human_attribute_name(attr) %></td>
<td>
<% if attr == "body" %>
<%= f.text_area attr, :rows => 60, :cols => 80, :class => "redactor" %>
<% else %>
<%= f.text_field attr, :value => resource.public_send(attr).to_s %>
<% end %>
</td>
</tr>
<% end %>
<%= f.fields_for :images_posts do |images_posts| %>
<%= images_posts.fields_for :image do |images| %>
<tr>
<td>Image</td>
<td><%= images.file_field :image %></td>
</tr>
<% end %>
<tr>
<td>Caption</td>
<td><%= images_posts.text_field :caption %></td>
</tr>
<% end %>
<tr class="dull">
<td colspan="2"><%= f.submit "Go" %></td>
</tr>
</tbody>
</table>
<% end %>
Models
#models/image_post.rb (the join model)
class ImagePost < ActiveRecord::Base
#Associations
belongs_to :post, :class_name => 'Post'
belongs_to :image, :class_name => 'Image'
#Validations
validates_uniqueness_of :post_id, :scope => :image_id
#Nested Association (Can upload & add images from form)
accepts_nested_attributes_for :image, :allow_destroy => true
end
#models/image.rb
class Image < ActiveRecord::Base
#Associations
has_many :products, :class_name => 'Product', :through => :images_products, dependent: :destroy
has_many :images_products, :class_name => 'ImageProduct'
has_many :posts, :class_name => 'Post', :through => :images_posts, dependent: :destroy
has_many :images_posts, :class_name => 'ImagePost'
has_many :brands, :class_name => 'Brand', :through => :brands_images, dependent: :destroy
has_many :brands_images, :class_name => 'BrandImages'
#Image Upload
Paperclip.options[:command_path] = 'C:\RailsInstaller\ImageMagick'
has_attached_file :image,
:styles => { :medium => "x300", :thumb => "x100" },
:default_url => "",
:storage => :s3,
:bucket => ''
:s3_credentials => S3_CREDENTIALS
#Validations
validates_presence_of :image, :message => "No Image Present!"
end
#models/post.rb
class Post < ActiveRecord::Base
#Images
has_many :images, -> { uniq }, :class_name => 'Image', :through => :images_posts, dependent: :destroy
has_many :images_posts, :class_name => 'ImagePost'
#Nested Association (Can upload & add images from form)
accepts_nested_attributes_for :images_posts, :allow_destroy => true
end
This was a BIG help for me: Rails nested form with has_many :through, how to edit attributes of join model?
Diagnosing Your Issue
I posted my code to give you a working example of what you can do (mine still needs refinement, but it works)
Looking at your code, you should add "accepts_nested_attributes_for" into your companies_users.rb model like this:
accepts_nested_attributes_for :user
In your companies model, change your accepts_nested_attributes_for to:
accepts_nested_attributes_for :companies_users

How to update attributes in many to many relation in rails?

I am new in rails. So i am not comprehending much of it. I have a database with three table. students table, courses table and registrations table.
My Railde models are as follows :
class Student < ActiveRecord::Base
attr_accessible :name
has_many :registrations
has_many :courses, :through => :registrations
validates :name, :presence => true
end
class Course < ActiveRecord::Base
attr_accessible :name
has_many :registrations, :dependent => :destroy
has_many :students, :through => :registrations
validates :name , :presence => true
validates :name, :uniqueness => true
end
class Registration < ActiveRecord::Base
attr_accessible :course_id, :student_id
belongs_to :course
belongs_to :student
validates :course_id, :student_id, :presence => true
validates :course_id, :uniqueness => {:scope => :student_id}
validates :student_id, :uniqueness => {:scope => :course_id}
end
......................
Controller action for updating student :
def update
#student = Student.find(params[:id])
if #student.update_attributes(params[:student])
redirect_to students_path, :notice => "Registration completed"
else
render 'edit'
end
end
................
View :
<%=form_for #student do |f| %>
<p>
<%= f.label :name, "Name" %>
<%= f.text_field :name %>
</p>
<p>
<%= render('course_list') %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
...............
_course_list partial :
Select Courses :<br/>
<p>
<% Course.all.each do |course| %>
<%=check_box_tag "student[course_ids][]", course.id, `enter code here`#student.course_ids.include?(course.id) %>
<%= course.name %> <br/>
<% end %>
</p>
.............................
when i submit the update button, i got an error
Can't mass-assign protected attributes: course_ids
.......
parameters :
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"j/lDE5bv1gWkfadQ6Cag6hGjg5nD2Ikad9vHOJTE7Pc=",
"student"=>{"name"=>"Galib",
"course_ids"=>["2",
"3"]},
"commit"=>"Update Student",
"id"=>"6"}
.........................
What i want to do is, if update button is clicked, both students table and registrations table need to be updated. Please help.
In models define the associations
class Student < ActiveRecord::Base
attr_accessible :name
has_many :registrations
has_many :courses, :through => :registrations
validates :name, :presence => true
accepts_nested_attributes_for :courses
attr_accessible :course_ids
end
class Course < ActiveRecord::Base
attr_accessible :name
has_many :registrations, :dependent => :destroy
has_many :students, :through => :registrations
validates :name , :presence => true
validates :name, :uniqueness => true
accepts_nested_attributes_for :students
end
class Registration < ActiveRecord::Base
attr_accessible :course_id, :student_id
belongs_to :course
belongs_to :student
validates :course_id, :student_id, :presence => true
validates :course_id, :uniqueness => {:scope => :student_id}
validates :student_id, :uniqueness => {:scope => :course_id}
accepts_nested_attributes_for :course
end
In Controller
def update
#student = Student.find(params[:id])
if #student.update_attributes(params[:student])
#student.courses.build
redirect_to students_path, :notice => "Registration completed"
else
render 'edit'
end
end
It may help you
The error is telling you that you have a permission error - course_ids can't be posted to from a form. More specifically, you have attr_accessible :name in the Student model which means that is the only attribute that can be saved when you save a Student record using a form (attr_accessible dictates what can be mass assigned).
Try changing your Student model to:
attr_accessible :name, :registrations_attributes
accepts_nested_attributes_for :registrations
You are trying to created a nested model form, so accepts_nested_attributes_for is used for this.
If you want to have the Registrations table updated, as well, you're going to have to tell the partial so that it knows that the partial is updating a different model than Student.
<%= f.fields_for :registrations do |registration| %>
<%= render('course_list') %>
<% end %>
In case of MongoDB, For implementing many to many in rails model you have to use has_and_belongs_to_many instead of simple has_many

accepts_nested_attributes_for with has_many polymorphic

I use paperclip to upload multi-file attached to studentcourseassignment,but i fail.
model
class StudentCourseAssignment < ActiveRecord::Base
attr_accessible :score, :comment, :finish_status,:attachments
accepts_nested_attributes_for :attachments
belongs_to :assignment
belongs_to :user
has_many :attachments ,:as => :attachmentable,:dependent => :destroy
end
class Attachment < ActiveRecord::Base
attr_accessible :user_upload
belongs_to :attachmentable , :polymorphic => true
has_attached_file :user_upload
end
controller
**new**
#sca = StudentCourseAssignment.new
#sca.attachments.build
#sca.attachments.build
**create**
#sca = StudentCourseAssignment.new(params[:student_course_assignment])
#assignment = Assignment.find(params[:assignment_id])
#sca.user = current_user
#sca.assignment = #assignment
if #sca.save
flash[:alert] = "success"
redirect_to course_years_path
else
flash[:alert] = "fail"
redirect_to course_years_path
end
** view**
<%= form_for #sca, :url => assignment_student_course_assignments_path(#assignment),
:html => { :id => 'student-assignment-form', :multipart => true } do |f| %>
file:
<%= f.fields_for :attachments do |a_f| %>
<%= a_f.file_field :user_upload %>
<%= submit_tag "create" %>
<% end%>
<% end %>
wrong
No association found for name `attachments'. Has it been defined yet?
if remove accepts_nested_attributes_for :attachments,it's still wrong
Attachment(#70201401779680) expected, got Array(#70201383294620)
hope your help!thx!
Change
from:
attr_accessible :score, :comment, :finish_status,:attachments
to:
attr_accessible :score, :comment, :finish_status,:attachments_attributes
I realize this is an old question, but fwiw I think you'll need to move
accepts_nested_attributes_for :attachments
to appear after
has_many :attachments, :as => :attachmentable,:dependent => :destroy
I hit this in a project once myself; pretty sure it boils down to accepts_nested_attributes_for expecting the relation to already be declared before its invoked.

Rails: how to add user ownership of a picture album in the album/new form?

Hi I'm currently working on my first rails project, a site for users to make albums and upload pics. I have the registration, logging in, and friending installed into my app. I'm trying to make it so that in the album creation form, you can see a list of your friends and select who you want to share access to the album with (meaning whoever you select would also be part of #album.users. I'm planning on using a checkbox (I can't think of any better way) to make this selection. However, I am not sure how to link the friendship model with the album/new form. This is how my form looks like:
album/new.html.erb
<%= form_for ([#user, #album]), :html => { :id => "uploadform", :multipart => true } do |f| %>
<div class="formholder">
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.check_box :friends %>
<%= f.label :description %>
<%= f.text_area :description %>
<br>
<%=f.submit %>
</div>
<% end %>
an error occurs on line #6 (
<%= f.check_box :friends %>
the error:
undefined method 'friends' for #<Album:0x007fa3a4a8abc0>
I can understand why, but I don't know how to fix it. I have the typical friendship join model to add friends, and I want to be able to see a list of all the friends and select them. I think a following step would be to add something like #album.users << #user.friendships.find_by_name(params[:friends]) in the create action in the albums controller, but I don't know how I would loop through the form that only returns one param for friends?
Here are my files:
Albums controller create action:
def create
#user = User.find(params[:user_id])
#album = #user.albums.build(params[:album])
# not so sure about the following line.
#album.users << #user.friendships.find_by_name(params[:friends])
respond_to do |format|
if #user.save
format.html { redirect_to user_album_path(#user, #album), notice: 'Album was successfully created.' }
format.json { render json: #album, status: :created, location: #album}
else
format.html { render action: "new" }
format.json { render json: #album.errors, status: :unprocessable_entity }
end
end
end
album model
class Album < ActiveRecord::Base
attr_accessible :name, :description
validates_presence_of :name
has_many :album_users
has_many :users, :through => :album_user
has_many :photos
end
user model
class User < ActiveRecord::Base
has_secure_password
attr_accessible :email, :name, :password, :password_confirmation
validates_presence_of :password, :on => :create
validates_format_of :name, :with => /[A-Za-z]+/, :on => :create
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
validates_length_of :password, :minimum => 5, :on => :create
has_many :album_users
has_many :albums, :through => :album_users
accepts_nested_attributes_for :albums
has_many :friendships
has_many :friends, :through => :friendships
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
album_user model (join table to make many-to-many relationship between album, which has many users, and users, which has many albums)
class AlbumUser < ActiveRecord::Base
belongs_to :album
belongs_to :user
end
friendship model
class Friendship < ActiveRecord::Base
attr_accessible :friend_id
belongs_to :user
belongs_to :friend, :class_name => "User"
end
let me know if you need any more info!! Thanks in advance!!!
You should add users_ids (yes, two "s") to the list of accessible attributes of Album, and then use a "select multiple" on the :users_ids field.
<%= f.collection_select(:users_ids, User.all, :id, :name, :multiple => true) %>

Has Many Through Checkboxes Not Saving Values Rails3

I've set up a has_many through relationship in my db and changed the keys because I'm working with a legacy db.
It all seems to be working but I cannot get the checkboxes to save to the database.
My models are as follows:
class Radcheck < ActiveRecord::Base
set_table_name 'radcheck'
attr_accessible :attribute_name, :username, :value, :op, :groupname
belongs_to :raduser
has_many :radusergroup, :dependent => :destroy, :primary_key => :username, :foreign_key => :groupname
has_many :radgroupcheck, :through => :radusergroup
end
class Radgroupcheck < ActiveRecord::Base
set_table_name 'radgroupcheck'
has_many :radusergroup, :dependent => :destroy#, :primary_key => :groupname, :foreign_key => :username
has_many :radcheck, :through => :radusergroup
end
class Radusergroup < ActiveRecord::Base
belongs_to :radcheck, :foreign_key => 'groupname', :primary_key => 'username'
belongs_to :radgroupcheck, :foreign_key => 'username', :primary_key => 'groupname'
end
In my form, I have this:
<% Radgroupcheck.all.each do |group| -%>
<%= check_box_tag :groupnames, group.id, #radcheck.radgroupcheck.include?(group), :username => 'radcheck[groupname][]' -%> | <%= label_tag :groupnames, group.groupname -%>
<% end -%>
The form renders the checkboxes ok and I can see the groupnames but nothing happens when I hit save.
The development log is clear and I can't see anything in the mysql query log either.
Try using this in your form:
<% Radgroupcheck.all.each do |group| -%>
<%= check_box_tag "radcheck[radgroupcheck_ids][]", radgroupcheck.id, #radcheck.radgroupchecks.include?(radgroupcheck), :id => "radcheck_radgroupcheck_id_#{radgroupcheck.id}" -%>
<%= label_tag "radcheck[radgroupcheck_ids][]", radgroupcheck.name, :for => "radcheck_radgroupcheck_id_#{radgroupcheck.id}" -%>
<% end %>
And in your controller:
def create
params[:radcheck][:radgroupcheck_ids] ||= []
#radcheck = Radcheck.new(params[:radcheck])
# rest of your controller logic
end
This is adapted from what worked for me in a Rails 3.1 project, based on http://railscasts.com/episodes/17-habtm-checkboxes?view=asciicast

Resources