Is using Playlist.new(params[:playlist]) ever not ok? - ruby-on-rails

Specifically in my new/create actions. I have #playlist = Playlist.new(params[:playlist]). The thing is I also have sensitive data in attr_accessible that I don't want them to modify (the number of listens on a playlist, which they shouldnt be able to update).
I tried Playlist.new(:title => params[:title], :description => params[:description], etc) but that didn't work. I assume because I need to do params[:playlist][:title] but this looks quite messy. Am I doing this incorrectly?

In the Model you can write a function called for example, new_safe which creates the new object with the params you want and then returns it
like this:
def new_safe(params)
playlist = Playlist.new
playlist.title = params[:title]
playlist.description = params[:description]
playlist.save
playlist
end
Just thinking, similiarly you could write it like this which is a bit cleaner
Controller:
#playlist = Playlist.new
#playlist.input_params(params)
Model:
def input_params(params)
playlist.title = params[:title]
playlist.description = params[:description]
playlist.save
end

Related

Ruby add variables to an existing object?

How can I add variables to an existing obejct?
I have a list of chat rooms and I want to add a new variable for each chat to use at my view:
Example I want to add total users of chat
def index
chats_all = ChatRoom.all
#chats = Array.new
chats_all.each |chat|
chat.total_users = 10
#chats << chat
end
#chats
end
total_users is not an attribute of ChatRoom class.
[EDIT - explaim better after #jvillian great awnser]
I don't want total_users as an attribute of User class.
I just want to add as a variable to use at this one single page. For json rails already let my add new attributes to objects. Just need to use as_json().map and a merge()
Example:
def index
chats = chats.as_json().map {
|chat|
chat.merge(
total_users: 10
}
response = { chats: chats }
render json: response
end
Now I got an json with chats and each chat has total_users attribute.
I want to know if I can do something like this with objects, just add a temporary variable to use at index page.
Try
class ChatRoom < ActiveRecord::Base
attr_accessor :total_users
end
You can read more in the docs.
Then, index could look like:
def index
#chats = ChatRoom.all.map do |chat|
chat.total_users = 10
chat
end
end
Alternatively, I would be tempted to do something like:
class ChatRoom < ActiveRecord::Base
TOTAL_USERS = 10
attr_accessor :total_users
def total_users
#total_users || TOTAL_USERS
end
end
And then:
def index
#chats = ChatRoom.all
end
Now, you'll get
#chats.first.total_users
=> 10
You can set total_users to something else if you like, but it will default to 10.
Here's a potential approach using OpenStruct:
def index
#chats = ChatRoom.all.map do |chat|
OpenStruct.new(
chat.
attributes.
merge!(total_users: 10)
)
end
end
Now, you can do:
#chats.each do |chat|
puts chat.total_users
end
which will return 10.
BTW and TBH, I do something like that last sort of thing (using OpenStruct or custom decorators) all the time. In my more recent apps, views never have direct access to models.
Maybe you want to send the response to the view as an array and scan to show informations?
def index
#chats = ChatRoom.all.as_json().map { |chat| chat.merge("total_users" => 10) }
end
Then access #chats, which is actually an array of hashes, view:
<% #chats.each do |chat| %>
<p><%= chat["total_users"] %></p>
<% end %>
You can check how #chats is structured by <p><%= #chats %></p>
I maybe made some syntax error.
To create temporary custom Objects without add new attributes to database Struct solve my problem.
I can create a Struct with chat room info and total users
chat_info = Struct.new(:name, :total_users, :messages)
chat_temp = []
chats = ChatRoom.where(condition)
chats.each do |chat|
chat_temp << chat_info.new("nome", 100, messages)
end

Ruby on Rails create new object with param from another

I have my search method and I want to pass my "search" to a analysis object. The search that user is looking will be the name of the analysis so as an Admin I can see the analysis and discovery what the users are most searching.
Here is my methods. My #analysis.name is always create with nil value. Does any body know how to fix that?
def search_articles
#search_param = params[:current_search][:search]
#articles = Article.where("title LIKE :search",
:search => "%#{params[:current_search][:search]}%")
search_attribute = :search
update_analysis(search_attribute)
end
def update_analysis(search)
#analysis = Analysis.create([{name: search, search_number: 1}])
end
Solution:
replace
search_attribute = :search
to
search_attribute = params[:current_search][:search]

How to delete a single instance from a collection

I'm trying to delete a single instance from a database query. "l.remove" represents what i want to do but i know its wrong. I have tried delete and destroy. destroy didn't work and delete actually removed the data from the database. I just want the data removed from the variable. Can anyone help me?
<%
#owner = User.find(params[:id])
#job_list = ShoppingList.where(:user_id=>#user.user_id)
#job_list.each do |l|
#temp = FlaggedCandidate.where(:flagged_user_id=>#owner.user_id, :list_id=>l.list_id)
if !#temp.nil?
l.remove
end
end
#candidate = FlaggedCandidate.new
%>
based on the code i assume that User has many ShoppingList.
You can do something like:
#job_list = #owner.shopping_lists.where( list_id: FlaggedCandidate.where( flagged_user_id: #owner.user_id ).pluck(:list_id) )
That could save the trouble of looping around.
You are trying to remove record from db. In order to just modify collection #job_list you need reject some unsatisfied elements. You can do it with select method (to select job_lists that flagged), or reject in opposite. This is how you code should looks like:
#owner = User.find(params[:id])
#job_list = ShoppingList.where(:user_id=>#user.user_id)
#job_list.select! do |job_list|
FlaggedCandidate.where(
:flagged_user_id => #owner.user_id,
:list_id => job_list.list_id
).any?
end
#candidate = FlaggedCandidate.new
select! simply change the original collection, instead of doing #job_list = #job_list.select { ... }

How can I combine the results of different variables into one variable?

I have following four variables in my controller index action which are retrieving data from different models as follows:
#forum = Forum.where(:user_id => #users.collect(&:user_id)).all
#poll=Poll.where(:created_by => #users.collect(&:user_id)).all
#article = Article.where(:user_id => #users.collect(&:user_id)).all
#jobpost = Jobplacement.where(:user_id => #users.collect(&:user_id)).all
I want to join all these variables' data into a single variable #post. How can I do this?
It is not good to have different type of objects in single collection.
But as you asked try
#post = [#forum,#forum,#article,#jobpost].flatten
Update:
I wrote this answer when I was a newbie in Ruby. When I look this answer I can not control my smile. The purpose of the flatten is to make a single array from the nested arrays. The answer does not relate to the question. But I am surprised about the upvotes :)
Put them in a hash:
#post = Hash.new
#post['forum'] = Forum.where(:user_id => #users.collect(&:user_id)).all
#post['poll'] = Poll.where(:created_by => #users.collect(&:user_id)).all
#post['article'] = Article.where(:user_id => #users.collect(&:user_id)).all
#post['job_placement'] = Jobplacement.where(:user_id => #users.collect(&:user_id)).all
They are not joined, but they are in one single variable. You can access them whenever you want, and do with them whatever you want.
Something like this:
conditions = { :user_id => #users } # assuming primary_key is set correctly
# in the User model
#post = Forum.where( conditions ).all +
Poll.where( conditions ).all +
Article.where( conditions ).all +
Jobplacement.where( conditions ).all
Or if you want to get fancy:
models = [ Forum, Poll, Article, Jobplacement ]
#post = models.reduce [] do |records, model|
records.push *model.where( :user_id => #users ).all
end
Note: .all might be unnecessary in both cases since it's usually called automatically by Rails when necessary, but I'm not certain.
I think you need like view model concept. Create a simple model class without inherit from ActiveRecord::Base and add all objects as attributes in the new class and initialize that.
class Post
attr_accessor :forum, :poll, :article, :jobpost
def initialize(forum,poll,article,jobpost)
#forum = forum
#poll = poll
#article = article
#jobpost = jobpost
end
end
In the controller action add the following;
#post = Post.new(#forum,#poll,#article,#jobpost)

Intercepting creation of new object

I'm adding a categorization functionality to my app and struggling with it. Objects have many categories through categorizations. I'm trying to intercept the creation of a new categorization, check if theres a similar one, if so, increment it's count, if not, create a new object. Here's what I have so far.
validate :check_unique
protected
def check_unique
categorization = Categorization.where(:category_id => self.category_id, :categorizable_id => self.categorizable_id, :categorizable_type => self.categorizable_type)
if categorization.first
categorization.first.increment(:count)
end
end
This kind of logic should not exist in the controller. This is really business domain and should be in the model. Here's how you should go about it:
categorization = Categorization.find_or_create_by_category_id_and_categorizable_id_and_categorizable_type(self.category_id, self.categorizable_id, self.categorizable_type)
categorization.increment!(:count)
find_or_create will try to find the category in the DB, and if it doesn't exist, it'll create it. Now just make sure that count defaults to zero, and this code will do what you want. (when initially created the count would be 1, then later it'll increment)
PS: I'm not sure if find_or_create has changed in rails 3. But this is the main idea
I decided to move it out of the model object and put it into the controller method creating the categorization. It now works (Yay!) and here's the code if anyone is interested.
def add_tag
object = params[:controller].classify.constantize
#item = object.find(params[:id])
#categories = Category.find(params[:category_ids])
#categories.each do |c|
categorization = #item.categorizations.find(:first, :conditions => "category_id = #{c.id}")
if categorization
categorization.increment!(:count)
else
#item.categorizations.create(:category_id => c.id, :user_id => current_user.id)
end
end
if #item.save
current_user.update_attribute(:points, current_user.points + 15) unless #item.categorizations.exists?(:user_id => current_user.id)
flash[:notice] = "Categories added"
redirect_to #item
else
flash[:notice] = "Error"
redirect_to 'categorize'
end
end

Resources