changing value of activerecord attribute - ruby

I have a problem and I am not sure how can I resolve it...
lets say I have a class User < ActiveRecord::Base and I have attribute factor:int that is my database, and I can access this atribute with User.find(x).factor.
Now, I have another table where i have changed_attributes, but not for all users.
So I want to rewrite attribute factor: when there is an entry in changed_attributes with user id, User.factor would be new, and if not, old factor would be returned.
I know this works:
class User < ActiveRecord::Base
def factor
newfact=20
newfact
end
end
but I dont know how to access old factor variable?
thank you
Dorijan
edit:
I have found the solution: read_attribute(:factor)

Related

Get instances during serializer validation in DRF

I am starting to work with the Django REST framework for a mini-reddit project I already developed.
The problem is that I am stuck in this situation:
A Minisub is like a subreddit. It has, among others, a field named managers which is ManyToMany with User.
An Ad is an advertising which will be displayed on the minisub, and it has a field named minisubs which is ManyToMany with Minisub. It has also a author field, foreign key with User.
I would like to allow these managers to add some ads on their minisubs through a DRF API. It is actually working. But I want to check that they put in minisubs only minisubs where they are managers.
I found a way like that:
class AdSerializer(serializers.HyperlinkedModelSerializer):
# ...
def validate_minisubs(self, value):
for m in value:
if user not in m.managers.all():
raise serializers.ValidationError("...")
return value
My question is: How to get user ? I can't find a way to get the value Ad.author (this field is set automatically in the serial data according to the user authentication). Maybe I don't find a way because there is no ways ? The place to do this is somewhere else ?
Thanks in advance.
You may get it out of the serializer this way:
class YourModelSeializer(serializers.HyperlinkedModelSerializer):
class Meta:
model=YourModel
def validate_myfield(self):
instance = getattr(self, 'instance', None)
...
I believe that this is a job for the permissions, if you are performing CRUD operations for inserting that into a database then u can have a permission class returns True if the user is a manager.
a permissions instance has access to the request which u can use to get the user and check if he is a manager:
http://www.django-rest-framework.org/api-guide/permissions/#custom-permissions

How can you make the id in the URL be random?

So I am looking for a way to create a randomized id that will link to a lobby that will be shown when the shown method is called in rails. As of right now, the url would look like this: http://localhost:3000/lobby/2. I'm looking to replace that 2 with a randomly generated id so you could send that link to friends if you want them to join your lobby. Any ideas?
You should share a bit more information as Gavin said. Knowing what you have already tried can help us give you more/better information on how to proceed.
I hope this sends you the right direction. For generating random IDs you can use SecureRandom:
http://ruby-doc.org/stdlib-1.9.3/libdoc/securerandom/rdoc/SecureRandom.html
I'd recommend you add another column to the lobbies table, and make it unique:
add_column :lobbies, :secure_token, :string, null: false
add_index :lobbies, :secure_token, unique: true
Now, in your Lobby model, whenever it is created, you can generate a unique token. For simplicity, you can do something along these lines:
class Lobby < ActiveRecord::Base
before_create :generate_unique_secure_token
# Rest of the model's code
private
def generate_unique_secure_token
begin
self.secure_token = SecureRandom.urlsafe_base64
end while self.class.exists?(secure_token: secure_token)
end
end
This will generate a secure_token every time a Lobby is created. Now in the controller you can use the secure_token instead of the id to find your Lobby. For example:
class LobbiesController < ApplicationController
def show
#lobby = Lobby.find_by(secure_token: params[:id])
end
end
I won't give you the whole answer since it's great to learn these things, but if you have any questions feel free to ask me!
This is where you should start: URLSafe Base 64
Here's a Railscasts episode that's soft of similar to what you want, see if you can expand from there! If you're new to Rails, be sure to check out Railscasts. All the pro episodes are available for free on youtube!

How to avoid multiple users page acess at same time and same record in rails?

Would like to display a message when click any product edit page if somebody
already opened/in that same record/page.
how to track users access on edit action for same record?ultimately i want to display message as "somebody already editing this product" to avoid overwrite
process between multiple users.
please share your ideas on it.
Naive solution for this might be adding an association say:
class Product < ActiveRecord::Base
belongs_to :edited_by, class_name: 'User', foreign_key: 'edited_by_user_id'
end
class User < ActiveRecord::Base
has_many :edits, class_name: 'Product', foreign_key: 'edited_by_user_id'
end
and then:
First comes on /edit page, set product.edited_by to that user.
Second user visits /edit page. You can check if edited_by for that product is set, then show him the message; blocking him to update the same product.
Remove the edited_by when user has updated the record.
But this comes at cost. There are lot of corner cases around this:
User might come on edit page and acquire edited_by association. But never update the record (thus never giving another user to update the product)
In case of some logic exception, edited_by might never be reset.
Involves devising a strategy when to reset if case #1 occurs.
Thus, I advise using Optimistic Locking instead. You can add a migration with :lock_version for your Product model. This will prevent the stale object from ever being saved in this scenario, preventing such conflicts.
It will raise the exception ActiveRecord::StaleObjectError when User #2(or first) tries to update an old record, which you can use to show your custom message by handling that exeption.
Hope that helps :)

User has_many posts. Get all users that have at least 1 post

Users have_many posts.
In a view, I want to get an alphabetized list of all users that have at least 1 post. Here is how I currently do it. Is there a way to make this all one line / using better Rails ActiveRecord conventions?
#users.order("name ASC").each do |user|
if user.posts > 0
...
end
end
Your current solution isn't bad (it's a single query) but it can be improved.
You can use ActiveRecord's built-in counter cache functionality to store the number of associated objects on the parent (in this case, the number of posts associated with a user). Then you can craft a query like this:
User.where('posts_count > 0').order('name ASC')
Here are the docs on :counter_cache (taken from here):
:counter_cache
Caches the number of belonging objects on the associate class through the use of increment_counter and decrement_counter. The counter cache is incremented when an object of this class is created and decremented when it's destroyed. This requires that a column named #{table_name}_count (such as comments_count for a belonging Comment class) is used on the associate class (such as a Post class) - that is the migration for #{table_name}_count is created on the associate class (such that Post.comments_count will return the count cached, see note below). You can also specify a custom counter cache column by providing a column name instead of a true/false value to this option (e.g., counter_cache: :my_custom_counter.) Note: Specifying a counter cache will add it to that model's list of readonly attributes using attr_readonly.
We can get all the user ids which have atleast one post using this.
Post.uniq.pluck(:user_id);
And then we can fetch all the user as follows.
User.order(:name).find(Post.uniq.pluck(:user_id));
User.joins(:posts).order('users.name asc') will perform an inner join, as described in the documentation here. A counter cache isn't a bad solution either.

Rails 4: Append to a "has_many" relation without saving to DB

In Rails 3 one can do things like some_post.comments.append(some_comment) where some posts is an instance of a model that "has_many" comments.
The problem I'm facing in Rails 4 is that the append method now saves to DB (like push and << ) and I need to just "append" without saving the appended object to the DB.
How do we achieve that in Rails 4? I can't use some_post.comments.build(some_comment.attributes) because I need to preserve the other relations already present in the some_comment instance.
It's oddly difficult to do this elegantly in Rails. This is the cleanest way I've found:
post.association(:comments).add_to_target(comment)
You could do:
class Post < ActiveRecord::Base
has_many: comments, autosave: false
...
end
Then << will just append and not save.
You can do it without using reflection on the association:
post.comments.build(
attr_1: value_1,
attr_1: value_2,
# Other comment attributes
)

Resources