How to update a single field in has_many object - activerecord

I am having a user object which has one-to-many relation with Address object. My class looks like this
class User
has_many :address
end
class Address
belongs_to :user
end
I want to update only city column in address table for a particular user.
How to do this?
I tried like this
#user.address.each do |a|
a.city = 'Alabama'
end
#user.save
But this is not working.

a.update_attributes(:city => 'Alabama')

This should work.
#user.address.update_all(:city => 'Albama')

Related

removing duplicate entry for csv import in ruby

while importing csv row i need to check wether this is duplicate entry or new entry.
my csv looks like this,
company,location,region,service,price,duration,disabled
Google,Berlin,EU,Design with HTML/CSS,120,30,false
Google,San Francisco,US,Design with HTML/CSS,120,30,false
Google,San Francisco,US,Restful API design,1500,120,false
Apple,London,EU,Design with HTML/CSS,120,30,false
Google,Berlin,EU,Design with HTML/CSS,120,30,false
Google,San Francisco,US,Restful API design,1500,120,false
Also the row value should be imported in different table whose association is like this
A Company:
can have multiple regions: US, EU and each region multiple branches, i.e. London, Berlin. Define a hierarchy to represent this logic.
has many Services. If there are more branches, they will all share the same services
can be disabled
A Service:
has a duration
has a price
can be disabled
if the company is disabled, all services are disabled.
for which i have implemented association like this
class Company < ApplicationRecord
has_many :regions
has_many :services
has_many :locations, through: :regions
end
class Region < ApplicationRecord
belongs_to :company
has_many :locations
end
class Location < ApplicationRecord
belongs_to :region
belongs_to :company
end
class Service < ApplicationRecord
belongs_to :company
end
How will I import this?
I am doing something like this
namespace :import do
desc "Import data"
task company: :environment do
CSV.foreach('lib/data/companies_data.csv', headers:true) do |row|
company = Company.create(:name => row["company"])
region = company.regions.create(:name => row["region"])
if region.id and company.id
location = company.locations.create(:name =>row["location"],
:region_id => region.id)
service = company.services.create(:name => row["service"],
:price => row["price"], :duration =>
row["duration"], :disabled =>row["disabled"])
end
end
end
end
How do I check wether a row is already present in database as it already contains associated table.
You can use .first_or_create. This will only create new db records if there is not a match on the previous ActiveRecord Relation call:
Model.where(some_unique_field: row['Unique Column']).first_or_create(row)
You can also pass a block to first_or_create as listed in the docs if you want to apply any additional logic to the CSV row ie model.price = row['price'] + fee

Attempting to create a database item using the has_one relationship, no exceptions, but still no item

Models:
A User has_one Ucellar
A Ucellar belongs_to User
I have confirmed from multiple sources that these are set up correctly. For posterity, here is the top portion of those two models.
class User < ActiveRecord::Base
has_many :authorizations
has_one :ucellar
validates :name, :email, :presence => true
This is actually the entire Ucellar model.
class Ucellar < ActiveRecord::Base
belongs_to :user
end
Ucellar has a column called user_id, which I know is necessary. The part of my application that creates a user uses the method create_with_oath. Below is the entire User class. Note the second line of the create method.
class User < ActiveRecord::Base
has_many :authorizations
has_one :ucellar
validates :name, :email, :presence => true
def create
#user = User.new(user_params)
#ucellar = #user.create_ucellar
end
def add_provider(auth_hash)
# Check if the provider already exists, so we don't add it twice unless authorizations.find_by_provider_and_uid(auth_hash["provider"], auth_hash["uid"])
Authorization.create :user => self, :provider => auth_hash["provider"], :uid => auth_hash["uid"]
end
end
def self.create_with_omniauth(auth)
user = User.create({:name => auth["info"]["name"], :email => auth["info"]["email"]})
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
EDIT:
Forgot to summarize the symptoms. On create, the user is in the db, with no exceptions thrown, and nothing to signify that anything went wrong. However, the related ucellar is never created. Per the documentation Here, the create method should create AND save the related ucellar.
It should create ucellar too.
Try to get the error messages after the creation by calling:
raise #user.errors.full_messages.to_sentence.inspect
I'm not sure why this wasn't working, but I ended up just moving this code out of the create action of the user controller, and putting it directly after an action that was creating a user. It solved my issue though. Thanks everyone for your help!

How to filter all ad by category name?

My use case is simple:
Get all ads that have a category name of params[:category_name].
Here are my model associations:
class Ad < ActiveRecord::Base
belongs_to :category
attr_accessible :anonymous, :celular, :name, :precio, :category_id
end
class Category < ActiveRecord::Base
has_many :ads
attr_accessible :name
end
Here is my controller code:
def by_category
#ads = Ad.where(:category => params[:category_name])
end
But it's not working as intended and I get an exception:
SQLite3::SQLException: no such column: ads.category: SELECT "ads".* FROM "ads" WHERE "ads"."category" = 'aeronautica'
How can I filter the ad objects by category name?
In your ads database you only have a column called category_id, so searching the ads database for a category name has no use.
Category.find_by_name(params[:category_name]).ads
This would show all ads for a category with the category_name that is in the params.
Ad.where(:category => {:name => params[:category_name]})
Ad.where(:category => Category.find_by_name(params[:category_name]))
params[:category_name] is only a string, whereas :category is an object of type Category.
Category.find_by_name
will give you a Category object, which you can compare with :category
Edit:
For this particular case, you could try the following, since you might've used category_id:integer instead of category:reference for creating the Ad model.
Ad.where(:category_id => Category.find_by_name(params[:category_name]).id)

Rails get related items through two different relationships

I have a "two middleman" model setup as shown below:
User
has_many :comments
has_many :ratings
Comment
belongs_to :user
belongs_to :movie
Rating
belongs_to :user
belongs_to :movie
Movie
has_many :comments
has_many :ratings
Whats the best way to get all Movies that a User is associated with (either commented on or rated)?
I'd like to be able to call User.get_movies(user_id) and get back an ActiveRecord::Relation object so that it's chainable (i.e. User.get_movies(user_id).limit(3).order(...)). This returns a regular old array, and I suspect I'm hitting the database way more than I need to be.
def self.get_movies(user_id)
user = self.where(:id => user_id).includes({:comments => :movie}, {:ratings => :movie})
movies = []
user.comments.each do |comment|
movies.push(comment.movie)
end
user.ratings.each do |rating|
movies.push(rating.movie)
end
movies.uniq!
end
def movies
Movie.includes(:ratings, :comments).where("`ratings`.user_id = ? OR `comments`.user_id = ?", self.id, self.id)
end
Untested, but I'm pretty sure using a joins instead of includes also works.

ActiveRecord :through to set default values on through table

I would like to set a default value in a has_many through association.
Lets say I have three models:
People
Friends
Dogs
A person can request that a dog becomes their friend.
So a person would create an association where friends has an active column = false.
User
has_many :friends
has_many :dogs, :through => :friends
Now when I assign a dog to a user
User.find(1).dogs << dog
The friends table has null in the active column.
My friends model is defined as
Friend
def initialize(args = {})
super(args)
active = false
end
yet this does not work because the friend object is never created. Do I have to manually create one?
To set default values of a model; In the model I do this
before_save :default_values
private
def default_values
self.status = :active unless self.status
end
Not sure if this is the correct approach though.
With the following code you'll create a new friend with active = false
class User < ActiveRecord::Base
has_many :friends, :conditions => "active = false"
has_many :dogs, :through => :friends
end
#user = User.new
#user.friends.create #or #user.friends.build

Resources