Accessing has_many model records - ruby-on-rails

I have the following 2 tables defined in migrations
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :name
t.string :phone
t.string :email
t.string :address
t.string :resume
t.timestamps
end
end
end
Class CreateResumeSections < ActiveRecordMigration
def self.up
create_table :resume_sections do |t|
t.string :section_name
t.string :html
t.timestamps
end
end
end
I have following 2 models
class User
has_many :resume_sections, :dependent => :destroy
attr_accessor :section_layout
after_save :save_sections
private
def save_sections
self.section_layout = ###Someother logic here that sets this variable
end
end
class ResumeSection
belongs_to :user
end
In my users_controller, I have the following code
class UserController < ApplicationController
def create
#user = User.new(params[:user])
#user.save
#user.section_layout.each {|key,value|
rs = ResumeSection.new(:section_name => key, :html => value, :user => #user)
rs.save
}
end
end
In my view I have the following code
<% #user.resume_sections.each do |section| %>
<%= section.section_name %>
<%= section.html %>
<% end %>
I get Undefined method error for Nil:NilClass in the view. The expression #user.resume_sections is not returning to me the records that I just created and saved in the UsersController. Instead it returns nil to me. When I check the database the records are there.
Is the expression #user.resume_sections the correct expression to access these records?
Thanks
Paul

It seems to me that your you missed something in you migrations. ResumeSection needs to have and integer field called user_id. Just create a new migration that has something like this in it:
def change
add_column :resume_section, :user_id, :integer
end

Related

How would I update a table everytime a specific attribute is updated? (lambda, maybe?)

So I created a new table to keep track of everytime a project in another table switches from active to inactive. I've successfully been able to add ALL of the projects and their active statuses but that isn't what I want.
#Here is the code for the status change table
class CreateActiveHistories < ActiveRecord::Migration[5.2] def change create_table :active_histories do |t| t.string :project t.string :active t.timestamps t.string :user end end end
and here is the code for the projects table these are just the attributes that I feel like are necessary to make my table work.
class CreateProjects < ActiveRecord::Migration[5.0]
def change
create_table :projects do |t|
t.references :customer, foreign_key: true
t.string :name
t.string :harvest_project_id
t.date :start_date
t.date :end_date
t.timestamps
end
end
end
#and adding the active column
class AddActiveToProjects < ActiveRecord::Migration[5.0]
def change
add_column :projects, :active, :boolean, default: true
end
end
#this is the code I have in my table currently for the active status
<td><%= project.name %></td>
<td><%= project_status %></td>
#This is my controller
def active_history
#project = Project.where(id: params[:id]).includes(:customer).take
#q = Project.ransack(params[:q])
#q.active_eq = true unless params[:q]
#projects = #q.result.includes(:customer, :project_hours, project_requirements: [:resource_requirements])
#project_names = Project.all.pluck(:name).uniq.sort
if #q.active_eq == true
#active = '1'
elsif #q.active_eq == false
#active = '0'
else
#active = '-1'
end
end
#and this is in my helper
def project_status
if #project.active == false
return "Active"
else
return "Inactive"
end
end
So, would I create a lambda that updates that table every time I want that table to update? This seems like it would be my best option but I have never used a lambda anywhere other than AWS and it's pretty much automized for you on there... SO ruby-railists... How would I do this on rails?

Rails has_many :through association: Updating all 3 models at the same time

This question follows up on Rails has_many :through association: save instance into join table and I am restating things here for more clarity.
In our Rails app, there are 3 models:
class User < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :calendars, through: :administrations
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
class Calendar < ActiveRecord::Base
has_many :administrations, dependent: :destroy
has_many :users, through: :administrations
end
And here are the corresponding migrations:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :email
t.integer :total_calendar_count
t.integer :owned_calendar_count
t.timestamps null: false
end
end
end
class CreateAdministrations < ActiveRecord::Migration
def change
create_table :administrations do |t|
t.references :user, index: true, foreign_key: true
t.references :calendar, index: true, foreign_key: true
t.string :role
t.timestamps null: false
end
end
end
class CreateCalendars < ActiveRecord::Migration
def change
create_table :calendars do |t|
t.string :name
t.timestamps null: false
end
end
end
Here is what we are trying to accomplish:
When a logged in user (current_user) creates a calendar, we should:
Create a new #calendar and save it to the Calendar table
Assign the "Creator" role to the user (current_user) for this newly created calendar through the Role column in the Administration table
Increment the total_calendar_count and the owner_calendar_count columns of the User table
In order to do that, we think we need to work on calendars#create.
In the CalendarsController, we already have the following code:
def create
#calendar = current_user.calendars.create(calendar_params)
if #calendar.save
flash[:success] = "Calendar created!"
redirect_to root_url
else
render 'static_pages/home'
end
end
And we collect data from users through the following _calendar_form.html.erb form:
<%= form_for(#calendar) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_field :name, placeholder: "Your new calendar name" %>
</div>
<%= f.submit "Create", class: "btn btn-primary" %>
<% end %>
We are considering updating the controller as follows:
def create
#calendar = current_user.calendars.create(calendar_params)
#current_user.total_calendar_count += 1
#current_user.owned_calendar_count += 1
current_user.administrations << #calendar.id
#calendar.administration.role = 'Creator'
if #calendar.save
flash[:success] = "Calendar created!"
redirect_to root_url
else
render 'static_pages/home'
end
end
ActiveRecord::AssociationTypeMismatch in CalendarsController#create
Administration(#70307724710480) expected, got Fixnum(#70307679752800)
unless record.is_a?(reflection.klass) || record.is_a?(reflection.class_name.constantize)
message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
raise ActiveRecord::AssociationTypeMismatch, message
end
end
app/controllers/calendars_controller.rb:7:in `create'
How can we make it work?
This line is actually causing the error: current_user.administrations << #calendar.id.
current.administrations expects an object of type Administration while you are passing a Fixnum into it.
You can accomplish the same functionality in the following way:
current_user.administrations.create(calendar_id: #calendar.id)
Edit:
As OP asked in comments that it is a good practice or not. See, there is rule that says that controllers should be skinny, and models should be fatty. Well, it means you should try to write minimum code, and all the logic and fetching of objects should be there in models. But that isn't the case in your code scenario. You should move your code into model, and then call that into your controller.
Here's how:
class User < ActiveRecord::Base
def add_calendar_and_role(calendar_id, role)
self.administrations.find_by(calendar_id: calendar_id).update(role: role)
end
end
This way, your code reduces to just:
current_user.add_calendar_and_role(#calendar.id, 'Creator')
And on the same way, you can further refactor your controller code.

How to make private activities?

How can we give the user the option to make activities private? This would give users privacy for posts they want for their eyes only.
Here was one of my attempts, which gives me:
NoMethodError in ActivitiesController#index
undefined method 'public_activities' for line: #activities = Activity.public_activities.order("created_at desc").where(current_user.following_ids)
class ActivitiesController < ApplicationController
def index #Added .public_activities
#activities = Activity.public_activities.order("created_at desc").where(user_id: current_user.following_ids)
end
end
class Activity < ActiveRecord::Base
belongs_to :user
has_many :comments, as: :commentable
belongs_to :trackable, polymorphic: true
def public?
!private
end
end
create_table "activities", force: true do |t|
t.boolean "private", default: false
t.integer "user_id"
t.string "action"
t.integer "trackable_id"
t.string "trackable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
class User < ActiveRecord::Base
has_many :activities
def public_activities
activities.find(&:public?)
end
end
And in one of the _forms, such as #valuations or #goals, is where the user can make the distinction via his submission:
<%= button_tag(type: 'submit', class: "btn", id: "gold") do %>
<span class="glyphicon glyphicon-plus"></span> Public
<% end %>
<%= button_tag(type: 'submit', class: "btn") do %>
<% :private %><span class="glyphicon glyphicon-plus"></span> Private
<% end %>
Much of this code was inspired from the answer here: How to use private submit to hide from profile?
Thank you!
class User < ActiveRecord::Base
has_many :activities
def public_activities
activities.find(&:public?)
end
end
This has defined a new instance method called public_activities - you will only be able to use it on an instance of a user
class ActivitiesController < ApplicationController
def index #Added .public_activities
#activities = Activity.public_activities.order("created_at desc").where(current_user.following_ids)
end
end
Here you are trying to call a class method on the Activity class instead.
If you want to do the above, then you'll need to create a scope on the Activity class.
in which case, it's better not to repeat the "activities" part in the name, but just call it "public"
eg
class Activity < ActiveRecord::Base
belongs_to :user
has_many :comments, as: :commentable
belongs_to :trackable, polymorphic: true
scope :public, ->{ where(:private => false) }
def public?
private == true ? false : true
end
end
class ActivitiesController < ApplicationController
def index
#activities = Activity.public.order("created_at desc").where(current_user.following_ids)
end
end

Form Creating nest objects

I have a nested object issue when creating a new item using forms. When I create a new Item within a form and view I created I get a nil on the Product object when trying to access it.
Here is my structure. I have a class called Item and a class called Product. There could be more than 1 item referring to the same Product.
class CreateItem < ActiveRecord::Migration
def change
create_table :items do |t|
t.integer :product_id
t.string :name
t.text :description
t.timestamps
end
end
end
class CreateProducts < ActiveRecord::Migration
def change
create_table :products do |t|
t.string :name
t.text :description
t.decimal :price
t.string :image_file_name
t.integer :inventory
t.timestamps
end
end
end
class Item< ActiveRecord::Base
belongs_to :product
belongs_to :itemstatus
end
class Product < ActiveRecord::Base
has_one :shop
accepts_nested_attributes_for :item
end
Controller Code:
def create
#item= Item.new(params[:item])
if #item.save
redirect_to #item, notice: "Item successfully created!"
else
render :new
end
end
The problem is happening when I go to show the created item. The Product object is nil. I'm not sure what I should be doing to get the Product Object correctly created and added in this process of creating a new Item.
Can someone help me?
Thanks!
params[:item] must be as the following:
#first example
params[:item] = {product_id: 1}
#second example
product = product.create(name: "", description: "", ..)
params[:item] = {product: product}
#third example
#item.product = product
#or
#item.product_id = params[:item][:product_id]
Try to do that:
#item.new(name: params[:item][:name], product_id: params[:item][:product_id], description: params[:item][:description])
help link

Rails3, Unknown key(s): client_id, on belongs_to association

I've been searching for a while now, but google isn't really helping me.
The ArgumentError Unknown key(s): client_id appears in the ProjectsController:
# projects_controller.rb
class Management::ProjectsController < Management::ManagementController
def index
#projects = Project.find( :client_id => current_user.client )
end
end
This is the project model:
# project.rb
class Project < ActiveRecord::Base
belongs_to :client
end
This is the client model:
# client.rb
class Client < ActiveRecord::Base
has_many :projects
end
And finally, the migration:
# 20110404155917_create_projects.rb
class CreateProjects < ActiveRecord::Migration
def self.up
create_table :projects do |t|
t.string :name
t.datetime :date
t.text :description
t.integer :client_id
t.timestamps
end
end
def self.down
drop_table :projects
end
end
Should be possible, right?
Can't see what I'm missing here..
Anyone got a suggestion?
Thanks!
Use
#projects = Project.where( :client_id => current_user.client.id)
or
#projects = Project.find_by_client_id(current_user.client.id)
or you could do
#projects = current_user.client.projects
Little bit cleaner perhaps?

Resources