How to show flash message of newly created resources? - ruby-on-rails

Lets say I have a Product model and my controller allows the creation of 5 new products all at once. What I do right now is render back to the same page but what I want to do is also render in the flash which products have been created. So it would say:
Successfully created: Milk, Soup, Cheese, Bread, Candy
instead of
Successfully created Products
How would this be done?

Something like this should work:
redirect_to :back, notice: "Succesfully created: #{#created_products.map(&:name).join(', ')}"
Assuming #created_products is an array of the products you just created and they each have an attribute called name.
Oh and of course you need this in your html:
<div class="notice"><%= notice %></div>

Just do this in your controller. You probably have a create action where you actually create these objects, and they problem have a name attribute or something, right? So when you create the objects, save them in an array, then use the map and join methods to put them together. Something like this:
def create
successful = []
# loop through the parameters
obj = MyModel.new(...)
if obj.save
successful << obj
end
# end loop
flash[:notice] = "Succesfully created: #{successful.map(&:name).join(', ')}"
redirect_to my_model_path
end
Map runs the method you pass in, so name, on each of the memebrs of the array and returns an array whose contents are the results of that method: in other words, you get an array of all their names. Join puts them together separated by whatever string you put in. So you'd get something like "Milk, cheese".

Related

Rails saving array with the duplicated elements

I'm populating an array with multiple elements (some of then are equals, thats what I want). My code is something like this:
def create
#order = Order.create()
#order.table = Table.find_by(:number => params['table'][0])
#products ||= []
#qtd = []
Product.all.each do |product|
params['order'].each_pair do |ordered|
if(product.id.to_s == ordered.first)
for i in 0..ordered.second[0].to_i
#order.products << product
#order.save
end
end
end
end
binding.pry #here the #order.products is the way I want to
if #order.save
flash[:success] = "Pedido criado com sucesso."
redirect_to tables_path
else
flash[:danger] = "Erro ao criar pedido."
render :new
end
end
But When I go to rails console and do Order.last.products he dosen't show me de duplicated elements like I saved on my controller. Whats happening?
Well in your case you should be sending order information from client to server like
"order"=>{"line_items_attributes"=>{"0"=>{"quantity"=>"4", "id"=>"127"}}}
Instead of repeating the product id in the list, your should implement a concept of line items in your system. Line Items are the objects representing items that are added to your shopping cart and instead of repeating the product_id you can use term quantity.
Now you can have separate model called LineItem. Order can have many LineItems. LineItem has many products.
For more info see What is a "order line"?
For current Implementation:
<< method does not allow duplicate entries. It filters out the duplicates. Its basically relates products with order since order can have multiple products via some_table. It cannot relate same product to the order twice.
My suggestion would be, create a string field(column) called products and add the serialized array of product ids.
order.products = [1, 1, 3, 4,4,4].to_s
while accessing you de-serialize.

How do I iterate through a hash in an objects param hash?

Rails (and coding) rookie here (I'm sure I'm just missing basic syntax structural stuff), I've created a form where the user can add as many field pairs as they like via AJAX (barely). This form will collect column titles for a 'sheet' and the associated data type (int, str... etc). The sheet will have item entries added later by users. I'm trying to make a Sheets controller create method that not only saves the title and description of the sheet, but also adds a record to the 'columns' table with the column title, data type and associated sheet id. When I submit the sheet form, I get the following params in the server terminal:
(sorry I'm not sure how to wrap the code snippet)
{"utf8"=>"✓", "authenticity_token"=>"yMlnfO1EWptkEXp5+9AGCO5C3vHt62EUHoKjdWoUB8I=", "sheet"=>{"title"=>"test 33", "description"=>"Descriptions"}, "column"=>[{"title"=>"1", "type"=>"num"}, {"title"=>"2", "type"=>"int"}, {"title"=>"3", "type"=>"real"}, {"title"=>"fo", "type"=>"no"}], "commit"=>"Save Specsheet!"}
I'm trying to loop through the column hash to create a record on the columns table. Each hash would use the title and type values as entries on the table.
My create method:
def create
#sheet = Sheet.new(sheet_params)
#sheet[:column].each do |key, value|
#column = Column.new
#column[:column_title] = key
#column[:column_data_type] = value
#column.save
end
if #sheet.save
redirect_to #sheet
else
flash[:error] = "Error saving sheet."
render :new
end
end
My error is usually something like this:
undefined method `each' for nil:NilClass
**#sheet[:column].each do |key, value|**
#column = Column.new
#column[:column_title] = key
#column[:column_data_type] = value
So I know I'm messing up referencing the column hash and its key and values. I'm thinking I can .reduce something here? I have no idea. These kinds of basic structural questions don’t really show up with googling, so please let me know what I'm doing wrong, and thank you for reading all of this! Cheers!
WORKING CODE (sorry for weird formatting)
def create
#sheet = Sheet.new(sheet_params)
column_params.each do |value|
#sheet.columns.build(value.permit(:title, :data_type))
end
if #sheet.save
redirect_to #sheet
else
flash[:error] = "Error saving sheet."
render :new
end
end
private
def sheet_params
params.require(:sheet).permit(:title, :description, :created_at, :updated_at, :column)
end
def column_params
params.require(:column)
end
When you are calling #sheet[:column], you are referencing an instance of Sheet instead of the params that you are trying to cycle through.
If you are trying to associate Columns to Sheets in a has_many relationship, you can create Columns like:
column.each do |key, value|
#sheet.columns.new(
column_title: key
column_data_type: value
end
end
(and then save block)
in your controller. Where column are the params. This will indicate that the column belongs to the sheet instance.
If you are trying to make the Column record without the associations, you can do
column.each do |key, value|
Column.new(
column_title: key
column_data_type: value
end
end
(and then save block)
(Both assuming that your fields are named column_title and not just title.)

Take random ids, then store those random ids into the db

so I'm working on a code snippet that essentially takes out 35 random ids from the table List.
What I would like to do to find the ids that got randomly generated, store them into a database called Status.
The purpose is to avoid duplication the next time I get a new 35 random ids from the List. So I never get the same random id twice.
Here's what I've tried, but been unsuccessful to get working.
#schedule = current_user.schedules.new
if #schedule.save
#user = User.find(params[:id])
Resque.enqueue(ScheduleTweets, #user.token)
#schedule.update_attribute(:trial, true)
flash[:notice] = "success"
redirect_to :back
else
flash[:alert] = "Try again."
redirect_to :back
end
and the worker:
def self.perform(user_token)
list = List.first(6)
#status = list.statuses.create
list.each do |list|
Status.create(list_id: "#{list}")
if list.avatar.present?
client.create_update(body: {text: "#{list.text}", profile_ids: profile_ids, media: { 'thumbnail' => 'http://png-1.findicons.com/files/icons/85/kids/128/thumbnail.png', 'photo' => 'http://png-1.findicons.com/files/icons/85/kids/128/thumbnail.png' } })
end
end
end
however the Status.create(list_id: #list) doesn't work.
Does anybody have any idea what is going on, and how I can make the list_ids get saved successfully to Status?
It's also associated:
list has many statuses, and status belongs to list
The following line of code is wrong:
Status.create(list_id: "#{list}") # WRONG
In your case the list variable is a List instance. And you're passing its string version to list_id which expects an integer.
Do this:
Status.create(list_id: list.id)
Or this:
list.statuses.create
I think the following will also work:
Status.create(list: list)

assigning values to model

I'm kinda new to coding on rails. It would be great if you could help me out with what I think might be noob question.Here's my code:
def create
#project = Project.new(params[:project])
if #project.save
redirect_to new_project_path
end
student=#project.student_str.split(";")
#users = User.where(:code => student)
#users.each do |c|
puts c.email
end
#users.each do |c|
puts "I'm here"
c.projects = "#{c.projects};#{#project.id}"
end
end
So, in the create method, Each time a new project is created a string called student_str is stored where the ID number of each student is seperated by a ";". I split that string to an array using the split function to get an array of student ID's. I have the puts c.email and puts "I'm here" to make sure the loops are working fine. I get the proper outputs on terminal.
The problem here is the
c.projects = "#{c.projects};#{#project.id}"
That simply does not seem to be working.
My model is not updated when this line is executed. I get no errors though.
Can you tell me what I might have to do to fix this?
thanks!
You have to call c.save after you updated the projects attribute. Otherwise the object is updated but not the database so the next time you load it the changes are gone.

nested attribute object is created three times instead of one

I have three models, booking, room and travellers.
Booking has many rooms
room has many travellers
Since I'm doing a multi-step wizard booking and rooms gets created first, the travellers are created later in the update action.
This is the log for the update action: http://pastie.org/private/it7onlg8bnurqkgv6mptrq
And this is the relevant methods and actions for creating the travellers:
The view action
def step3
#booking = Booking.find_by_random_url_key(params[:id])
#variant = #booking.variant
#booking.rooms.collect {|room| room.number_of_persons.times {room.travellers.build} if room.travellers.blank?}
render :partial => "bookings/partials/step3", :layout => "booking"
end
room.number_of_persons method just return an int.
Relevant part of the update action
..
elsif #booking.update_attributes(params[:booking]) && #booking.aasm_state == "step3"
redirect_to booking_step4_url(#booking)
#booking.next!
..
next! is just a aasm transition
If I do a create in the console
Room.last.travellers.create(:forename => "john", :country_name => "Germany")
Only one object is created and even if I go back in the view and submit again he correctly updates the created object and does not create new ones.
#booking.rooms.collect {|room| room.number_of_persons.times {room.travellers.build} if room.travellers.blank?}
This looks wrong to me. You're initiating travellers but not storing them and collecting an array but not doing anything with it. Also, I understand you want to create a number of travellers but you condition on travellers being blank.
#travellers = #booking.rooms.collect { |room| room.number_of_persons.times { room.travellers.build } }
I got this to work by doing a create in the model instead of doing it through the forms.
So basically after the rooms are created I do:
self.rooms.map {|r| r.number_of_persons.times {r.travellers.create}}

Resources