I am developing a website in Ruby on Rails, MySQL, and Javascript.
The website is modular, meaning that a user can customize their homepage and drag and drop one module to another area where it will live. there are three columns where the module can be dropped. (Think iGoogle or Netvibes)
What is the best way to store this data, so that when the user returns their homepage can be reconstructed quickly?
I've considered doing it in a way where each module get's an ID that corresponds to the user, it's row and it's positiong in that row. (So something like.. user|column|row, would equal 1204|3|27, meaning that for user #1204 this module would be in column #3 and 27 spaces from the top.
Then when the user returns, just loop through, adding 1 to each until it reaches the end of the column and start again at the other one until all 3 columns are populated.
I feel like this would be very slow though, and there must be a better way to do it.
Any suggestions? Mostly looking for Database structure, but if you have some Rails code that would corrilate to this I wouldn't mind seein git.
I think the best is to keep your data in a single text field
For example 1204|3|27 should be in a text field ... with a good index per user id you should get the configuration very very fast. After that you just need to "explode" your configuration for "|" .
Regards
I say model it very straightforwardly:
class ModuleInstallation < AR::Base
belongs_to :user
belongs_to :module
validates_presence_of :column
validates_presence_of :row
end
class User < AR::Base
has_many :module_installations, :order => :column
has_many :modules, :through => :module_installations
end
Then let your controller handle any more sorting, something like this (untested, but look through it and the documentation for the methods I'm using to get the concepts):
#columns = current_user.module_installations.group_by(&:column)
#columns.each { |column, modules| modules.sort! { |x,y| x.row <=> y.row } }
Then your view is relatively simple:
<% #columns.each do |column, modules| %>
<div class="column-<%= column %>">
<% modules.each do |module| %>
<div class="module">
<%= module.to_html %>
</div>
<% end %>
</div>
<% end %>
Related
Quite new to rails and can't figure out how to build a dynamic menu bar.
The database uses a simple method to store menu items:
id | title | url | parent | position
--------------------------------------------------------------------
1 Books /books 0 1 (first link on menu bar)
2 Fiction /books/fiction 1 1 (first link under Books menu)
3 CDs /cd 0 2 (second link on menu bar)
4 Fantasy /books/fantasy 1
5 Singles /cd/single 2
6 Albums /cd/album 2
I need to get all entries in this table and display them according to their parent.
All the items with parent 0 will show on the menu bar.
When user hovers any parent, all its child elements are listed below it.
When I did this in PHP, I used a loop that resulted in many database calls; One to get all the parent items in position order (as the admin can change the order in which the parent items appear on the menu), and then one for each parent to get all its child elements (also in position order).
I then added each resulting item to an array that was named after the parent_id and finally concatonated the arrays.
$item[$parent][] = '<a href...'
I know the SQL was inefficient (and the PHP probably was, too) but it didn't matter back then. Now it does.
Any idea how I can make this work efficiently in ruby?
Let's assume that the database table that stores this menu information is called nav_items. Then the Rails convention would be to have a model called NavItem:
# app/models/nav_item.rb
class NavItem < ApplicationRecord
has_many :child_menu_items, class_name: NavItem, inverse_of: :parent_menu_item, foreign_key: :parent
belongs_to :parent_menu_item, class_name: NavItem, foreign_key: :parent, inverse_of: :child_menu_items
scope :top_level, { where("parent = ?", 0) }
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :populate_nav_vars
private
def populate_nav_vars
#nav_items = NavItem.top_level
end
end
# app/view/layouts/_nav.html
# #nav_items is defined in the controller as NavItem.top_level
# the nav structure is shown here as nested <ul> lists
# it can be rendered appropriately with css (e.g. Bootstrap)
<ul>
<%- #nav_items.each do |top_level_item| %>
<li><%= top_level_item.title %></li>
<li>
<ul>
<%- top_level_item.child_menu_items.each do |child_item| %>
<li><%= child_item.title %>
<%- end %>
</ul>
</li>
<%- end %>
</ul>
You really shouldn't worry about performance, it should not be noticeable at all. I assume here that you want the navigation menu on every page, so the convenient place to populate the required variables is in ApplicationController and populate the variable in a before_action callback.
If the performance issue concerns you, then you should make the navigation page elements a view partial, and apply rails caching to the partial.
I apologize for the newbie questions still relatively new to rails. I'm trying to show all the users who have liked a current user's specific items. With the help of the SO community and looking at different Rails guides - I'm 85% there. Currently, I'm displaying all users who have liked all items (not just my specific ones which is what I want) I've listed below all the relevant simple code - thank you so much guys!!
Index.html.erb
<%- #likers.each do |liker| %>
<%= image_tag liker.avatar, width: 25, class: "css-style" %> 
<%= liker.username %>
<% end %>
Items_controller
def index
#items = Item.order("created_at DESC")
if current_user.present?
#likers = Item.where("user_id", current_user.id).map(&:users).flatten
end
end
So, you want all #likers to be all the people who like the current_user's items?
#likers = current_user.items.map(&:likes).flatten.map(&:user).flatten.uniq
I've added the uniq so if a user likes more than one of these posts, you won't see them turn up multiple times. You can omit that, of course, if you want duplicates.
I'm also making some guesses about your other models based on your previous question, so you might need to tweak it depending on your actual implementation.
I'm very very very new to Rails, and I've got a fast approaching deadline to code my first rail app as part of a challenge.
I've so far created the basic blog application, to get my head around how rails works.
I need to display a list of all data held within a table on a page in my site. In blog, I've got an index page - which lists all blog posts so I've been trying to follow the same process.
I've created a populated table in my database, and a controller - but when I try and display info from that database on my page I get the following error:
uninitialized constant RecordsController::Aliens
class RecordsController < ApplicationController
def index
#records= Records.all
end
end
All I want to achieve is a simple table, which has the list of my records in, so far I'm not having much luck retrieving the data from the database.
Any help appreciated!
I assume you want to list all aliens am I right?
As your model is called Alien you can call it like that:
def index
#aliens = Alien.all
end
And then in your view something like:
<% #aliens.each do |alien| %>
<div class="alien">
<ul>
<% alien.attributes.each do |attr_name, attr_value| %>
<li><strong><%= attr_name %>:</strong> <%= attr_value %></li>
<% end %>
</ul>
</div>
<hr>
<% end %>
I have Rails app with a use case to display prices in a collection_select dropdown box. For instance, names of products and their prices, or clients and amounts owing.
I well know it's bad MVC practice to simply include the relevant helpers to get access to functions like number_to_currency, but the best I can do with a custom method on the Product or Payment model is get a value that looks like $20.2. So, it's readable but sub-optimal in that most users of the system will be expecting twenty dollars and twenty cents to be represented as $20.20.
Does anyone have any suggestions for easily customising the text_method of a collection_select?
The text_method as well as the value_method in collection_select accepts a symbol but also a lambda/proc block which will get the current collection element as a parameter. See the docs here. The lambda is executed in the context of the view so all view helpers should be available inside it.
So to get the model price formatted by a currency formatter you should be able to call collection_select like the following:
<%= collection_select :user, :payment_id, #user.payments,
:id, ->(pmt) { number_to_currency(pmt.amount) } %>
You have not shown your model associations, so this is just an example of a user having many payments for which you want to format the price in the select box text.
Abandon ship with the collection_select method, and just use select in your view:
<% options = #payments.each { |p| number_to_currency(p.price), p.id } %>
<%= f.select :payment, options %>
Since you're in the view, everything you'd expect is there, both model and helper methods.
I'm making assumptions on your HTML since you didn't give a specific example, but I think the code block above is everything you need to get going. For more details: http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-select
If you are married to collection_select, you could always roll your own number formatter for currency; shouldn't be difficult with pure Ruby. But, the method above will be more powerful in the long run and afford your more options with helpers down the line, and let you use functions consistently across views.
I ended up building on GoGoCarl's suggestion, but moving the array generation to a helper:
module PaymentsHelper
def invoices_for_payment_select(invoice)
#invoices.collect { |i| ["#{i.client.name} - #{number_to_currency(i.outstanding)}", i.id] }
end
end
This way I can reuse the dropdown box should I need to and keep the view neat.
I am displaying a list of all users (from a Users model) in my Rails 3 application. In a helper (in this case it's Faults) I have the following:
def user_all_select_options
User.all.map{ |user| [user.name, user.id] }
end
In the view I have the following:
<%= f.select :user_id, user_all_select_options %>
This simply creates a drop down list with the first users name pre-selected as it is at the top of the list. What I am trying to do is add an instruction(?) at the top of the list that is unselectable. The idea is to prevent the top user from getting constantly accidentally set as the required user even when they don't want to be.
So rather than the select box looking like this:
I would like it to look like this:
Is this possible, if so, how??
Pass the :prompt option.
<%= f.select :user_id, user_all_select_options, :prompt => 'Select a user' %>