Error deleting record in console ruby on rails - ruby-on-rails

I am trying to delete a record using the console. I have a model for "User". I tried several methods in the console:
a = User.where(:id => '18')
a.destroy
a.delete
User.where(:id => '18').destroy
User.where(:id => '18').delete
Using all of these methods, I got the same error: "Wrong number of arguments (0 for 1)"
Does anyone know what I am doing wrong?
Thx!

Try:
a = User.find(18)
a.destroy
When we use where, result will be ActiveRecord::Relation, means multiple records, on which you can't call destroy directly. You will need to call destroy by iterating over the result.
users = User.where(:id => 18)
users.each do |user|
user.destroy
end

I can add something here, The issue with your code that you are passing string while it expects an integer 'Number'
Your code should be as the following:
a = User.where(:id => 18).first
a.destroy
Without using first array of object will be returned and you can't use destroy method directly on it, in case you don't want to add first then your code should be like:
a = User.where(:id => 18)
a.each do |obj|
obj.destroy
end

Related

Rails iterate over objects array

I want to do something like this
#groups = Community::GroupMember.where(:member_id => current_user.id)
user_ids = []
#groups.each do |group|
user_ids << #group.community_group_members.where(:group_id => group.id).pluck(:member_id)
end
But I get error NoMethodError - undefined method `community_group_members' I think im not iterating #groups properly the way I want.
You should have:
user_ids << group.community_group_members.pluck(:member_id)
(group instead of #group). It's because inside each block, the element of your array is represented by local variable (which is unprefixed) instead of instance variable (prefixed by #). So #group instance variable is unset and thus evaluated to nil, which doesn't respond to community_group_members method.
Also, I deleted your where clause, since it's reduntant - you're already doing this in group.community_group_members call.
#groups = Community::GroupMember.where(:member_id => current_user.id)
user_ids = []
#groups.each do |group|
user_ids << group.community_group_members.where(:group_id => group.id).pluck(:member_id)
end
Does using the block variable group instead of #group work?
Assuming you have two models Community::Group and Community::GroupMember with associations has_many :community_group_members and belongs_to :community_group respectively, your first line:
#groups = Community::GroupMember.where(:member_id => current_user.id)
returns an array of Community::GroupMember instances, i.e. group members, not groups.
To get the associated groups you could use map:
#group_members = Community::GroupMember.where(member_id: current_user.id)
#groups = #group_members.map { |group_member| group_member.community_group }
or a join:
#groups = Community::Group.joins(:community_group_members).where(community_group_members: { member_id: current_user.id })
You can now retrieve the member_ids with:
user_ids = Community::GroupMember.where(group_id: #groups).pluck(:member_id)

RoR: first_or_initialize block doesn't save

I have the following code, which works fine with no errors but the models never get saved...
myarray.each do |item|
r = MyModel.unscoped.where(:site_id => #site.id, :url => item['permalink_url']).first_or_initialize do |r|
r.title = 'asdasdadaddjfgnfd'
r.save!
end
end
Terminal shows the SQL SELECT statements when attempting to find the Models, but the UPDATE/INSERT statements never run.
What am I missing here?
Rails first_or_* methods invoke passed block only for initialize or create part. If the record is found, the methods just return it so passed block will never run. Check the source
So you can use block in first_or_* methods only to initialize new items, not to update existing ones. Most likely, records with such conditions exist and don't get updated.
Try to move update code, something like
myarray.each do |item|
r = MyModel.unscoped.where(:site_id => #site.id, :url => item['permalink_url']).first_or_initialize
r.title = 'asdasdadaddjfgnfd'
r.save!
end
I solved this by using:
.first_or_initialize.tap() do |r|
But the comments below are also relevant
You're looking for first_or_create. first_or_initialize just initializes the object (possibly to prep for saving, but it doesn't have to be).
You're existing code would likely work as follows:
r = MyModel.unscoped.where(:site_id => #site.id, :url => item['permalink_url']).first_or_initialize do |r|
r.title = 'asdasdadaddjfgnfd'
end
r.save!

Check if record exists from controller in Rails

In my app a User can create a Business. When they trigger the index action in my BusinessesController I want to check if a Business is related to the current_user.id:
If yes: display the business.
If no: redirect to the new action.
I was trying to use this:
if Business.where(:user_id => current_user.id) == nil
# no business found
end
But it always returns true even when the business doesn't exist...
How can I test if a record exists in my database?
Why your code does not work?
The where method returns an ActiveRecord::Relation object (acts like an array which contains the results of the where), it can be empty but it will never be nil.
Business.where(id: -1)
#=> returns an empty ActiveRecord::Relation ( similar to an array )
Business.where(id: -1).nil? # ( similar to == nil? )
#=> returns false
Business.where(id: -1).empty? # test if the array is empty ( similar to .blank? )
#=> returns true
How to test if at least one record exists?
Option 1: Using .exists?
if Business.exists?(user_id: current_user.id)
# same as Business.where(user_id: current_user.id).exists?
# ...
else
# ...
end
Option 2: Using .present? (or .blank?, the opposite of .present?)
if Business.where(:user_id => current_user.id).present?
# less efficiant than using .exists? (see generated SQL for .exists? vs .present?)
else
# ...
end
Option 3: Variable assignment in the if statement
if business = Business.where(:user_id => current_user.id).first
business.do_some_stuff
else
# do something else
end
This option can be considered a code smell by some linters (Rubocop for example).
Option 3b: Variable assignment
business = Business.where(user_id: current_user.id).first
if business
# ...
else
# ...
end
You can also use .find_by_user_id(current_user.id) instead of .where(...).first
Best option:
If you don't use the Business object(s): Option 1
If you need to use the Business object(s): Option 3
In this case I like to use the exists? method provided by ActiveRecord:
Business.exists? user_id: current_user.id
with 'exists?':
Business.exists? user_id: current_user.id #=> 1 or nil
with 'any?':
Business.where(:user_id => current_user.id).any? #=> true or false
If you use something with .where, be sure to avoid trouble with scopes and better use
.unscoped
Business.unscoped.where(:user_id => current_user.id).any?
ActiveRecord#where will return an ActiveRecord::Relation object (which will never be nil). Try using .empty? on the relation to test if it will return any records.
When you call Business.where(:user_id => current_user.id) you will get an array. This Array may have no objects or one or many objects in it, but it won't be null. Thus the check == nil will never be true.
You can try the following:
if Business.where(:user_id => current_user.id).count == 0
So you check the number of elements in the array and compare them to zero.
or you can try:
if Business.find_by_user_id(current_user.id).nil?
this will return one or nil.
business = Business.where(:user_id => current_user.id).first
if business.nil?
# no business found
else
# business.ceo = "me"
end
I would do it this way if you needed an instance variable of the object to work with:
if #business = Business.where(:user_id => current_user.id).first
#Do stuff
else
#Do stuff
end
Something new to try (:
Assign a variable or return
return unless #business = Business.where(user_id: current_user.id).first
Method would exit at this point if there are no businesses found with current user's ID, or assigns instance variable #business to the first business object.

In Rails, what is the best way to update a record or create a new one if it doesn't exist?

I have a create statement for some models, but it’s creating a record within a join table regardless of whether the record already exists.
Here is what my code looks like:
#user = User.find(current_user)
#event = Event.find(params[:id])
for interest in #event.interests
#user.choices.create(:interest => interest, :score => 4)
end
The problem is that it creates records no matter what. I would like it to create a record only if no record already exists; if a record does exist, I would like it to take the attribute of the found record and add or subtract 1.
I’ve been looking around have seen something called find_or_create_by. What does this do when it finds a record? I would like it to take the current :score attribute and add 1.
Is it possible to find or create by id? I’m not sure what attribute I would find by, since the model I’m looking at is a join model which only has id foreign keys and the score attribute.
I tried
#user.choices.find_or_create_by_user(:user => #user.id, :interest => interest, :score => 4)
but got
undefined method find_by_user
What should I do?
my_class = ClassName.find_or_initialize_by_name(name)
my_class.update_attributes({
:street_address => self.street_address,
:city_name => self.city_name,
:zip_code => self.zip_code
})
Assuming that the Choice model has a user_id (to associate with a user) and an interest_id (to associate with an interest), something like this should do the trick:
#user = User.find(current_user)
#event = Event.find(params[:id])
#event.interests.each do |interest|
choice = #user.choices.find_or_initialize_by_interest_id(interest.id) do |c|
c.score = 0 # Or whatever you want the initial value to be - 1
end
choice.score += 1
choice.save!
end
Some notes:
You don't need to include the user_id column in the find_or_*_by_*, as you've already instructed Rails to only fetch choices belonging to #user.
I'm using find_or_initialize_by_*, which is essentially the same as find_or_create_by_*, with the one key difference being that initialize doesn't actually create the record. This would be similar to Model.new as opposed to Model.create.
The block that sets c.score = 0 is only executed if the record does not exist.
choice.score += 1 will update the score value for the record, regardless if it exists or not. Hence, the default score c.score = 0 should be the initial value minus one.
Finally, choice.save! will either update the record (if it already existed) or create the initiated record (if it didn't).
find_or_create_by_user_id sounds better
Also, in Rails 3 you can do:
#user.choices.where(:user => #user.id, :interest => interest, :score => 4).first_or_create
If you're using rails 4 I don't think it creates the finder methods like it used to, so find_or_create_by_user isn't created for you. Instead you'd do it like this:
#user = User.find(current_user)
#event = Event.find(params[:id])
for interest in #event.interests
#user.choices.find_or_create_by(:interest => interest) do |c|
c.score ||= 0
c.score += 1
end
end
In Rails 4
You can use find_or_create_by to get an object(if not exist,it will create), then use update to save or update the record, the update method will persist record if it is not exist, otherwise update record.
For example
#edu = current_user.member_edu_basics.find_or_create_by(params.require(:member).permit(:school))
if #edu.update(params.require(:member).permit(:school, :majoy, :started, :ended))

How do you mock params when testing a Rails model's setter?

Given the code from the Complex Form part III how would you go about testing the virtual attribute?
def new_task_attributes=(task_attributes)
task_attributes.each do |attributes|
tasks.build(attributes)
end
end
I am currently trying to test it like this:
def test_adding_task_to_project
p = Project.new
params = {"new_tasks_attributes" => [{ "name" => "paint fence"}]}
p.new_tasks_attributes=(params)
p.save
assert p.tasks.length == 1
end
But I am getting the following error:
NoMethodError: undefined method `stringify_keys!' for "new_tasks_attributes":String
Any suggestions on improving this test would be greatly appreciated.
It looks as if new_task_attributes= is expecting an array of hashes, but you're passing it a hash. Try this:
def test_adding_task_to_project
p = Project.new
new_tasks_attributes = [{ "name" => "paint fence"}]
p.new_tasks_attributes = (new_tasks_attributes)
p.save
assert p.tasks.length == 1
end
Can we see the whole stack trace? Where does it think String#stringify_keys! is being called?
Also, params looks odd to me. Is tasks.build() expecting input like this: ["new_tasks_attribute", {"name" => "paint fence"}] ?
If not, maybe you actually want Hash#each_key() instead of Hash#each()?
Need more data. Also, you might consider a Ruby tag to accompany your Rails tag.

Resources