How to show content if current_user meets the requirements - ruby-on-rails

How should I write a if condition in the view using Slim? I would like to show content if the current_user is a subscriber. I have a subscriptions table with a user_id and cancelled column. User has access to the website if their id can be found in the subscriptions table under user_id and the cancelled column is NULL. If cancelled has a 1 value then the user no longer has access.

If you have your relationship set up, something like this as an instance method in the user model should work.
def subscribed?
subscriptions.where(cancelled: nil).exists?
end
Then in the view, you can do something like:
<% if user.subscribed? %>
Here ya go
<% else %>
Go away
<% end %>
You could obviously just put the logic in the subscribed? method in the view, but this is a little cleaner, maybe.

Related

Using Thumbs_up to display users who voted on a post

I'm using Thumbs_Up gem to let users vote on a post(called Topic). I've done the voting part but now I want to display the users who voted on that particular post. I'm very new to Ruby On Rails, and I'm stuck at the view part.
Here's my controller: app/controllers/topics_controller.rb
def vote_who
#topic = Topic.find(params[:id])
#vote_list=#topic.voters_who_voted_for
end
In my index.html.erb, I want to display the names of there users who voted on that post. This should be right next to the vote button. Kind of like this,
But how do I send back information from the controller?
Or is this approach completely wrong?
IMHO, it's more preferable to show all voters in the 'show' view of the each particular Topic (imagine you have 100 voters for one topic, what this table in index view will look like?).
This way you don't need any distinct action (due to Rails conventions 1 action == 1 view (in general)). Just put in your show action:
def show
#topic = Topic.find(params [:id])
#vote_list = #topic.voters_who_voted_for
end
Then in your view (show.html.erb) you need to do something like this:
<% #vote_list.each do |voter| %>
<%= voter.email %> #or login, or name, or any user's attribute you want to display in your list
<% end %>
Or even try to simplify this: leave show action in your TopicsController as it is (don't create any #vote_list variable, only find right Topic), and call voters_who_voted_for method inside your show view, e.g.:
<%= #topic.title %>
<%= #topic.body %>
<%= #topic.voters_who_voted_for %>

Rails - Submit multiple forms on same page

Model:
Users have expenses. Expense has a status.
View:
As users add their expenses, they are shown in a list. Each expense row has a form button on the end, which is used to submit the expense (changing the status of the expense). This allows users to add expenses they have not completely filled out, and submit them when they are ready. There is no parent form on this page, just the form buttons which submit the expense to a method which changes the status, and then reloads the page.
Currently it works great, but users have asked to be able to "submit all" the expenses that are showing on the view with a single button.
Question:
What is the proper way to handle this in rails? Should I find a way to gather the array of expense id's and then submit a separate form? Is there a way to ask for a set of records present in a view with a certain status?
Thanks!
Another option, if I'm thinking about this right (big if), would be to wrap your page in a User form. Then you could have something like...
<%= form_for(#user) do |f| %>
<% #user.expenses.each do |expense| %>
<% f.fields_for expense do |e| %>
<!-- expense form -->
<% end %>
<% end >
<% end %>
This is something you could submit as a whole. I'm having trouble picturing what a single expense addition might look like, but hopefully this gets you a little further down the road.
Edit: in addition to having this User form on the page, you could have an "extra" Expense form to create an expense. When you submit a new expense, that expense appears in the list under the user form, where it can be edited or submitted, either as part of a group or individually (as part of a "group" of 1).
custom controller action:
def update_all_expense_statuses
expenses = current_user.expenses
ExpenseUpdater.new(expenses).update_expense
redirect_to :back
end
expense updater class:
class ExpenseUpdater
def initialize(expenses)
#expenses = expenses
end
def update_expense
#expenses.each do |expense|
expense.update_attributes(status: 'paid')
expense.save
end
end
end
This is just an example of one way to update all the user's expenses with a custom controller action. Just call the controller method from a link_to:
<%= link_to "Update all expenses", update_all_expense_statuses_path %>
Remember to add it to your routes. Hope this helps.
The first thing you should do is change the forms to submit remotely, ie make an ajax request. Then you're not reloading the whole page. Check out Rails' various "remote" form helpers, eg "remote_form_for".
Then, write a javascript function to submit all the forms for inputs that have changed since the page loaded. You'd probably want to add a "changed" (or similar) class to the parent form in an onchange event in each input, to facilitate this. I think this is the best way to handle the "status" thing you're asking about. Make a "Submit all" button which calls this function.
Use a form/service object http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/ to encapsulate expense report

ruby on rails get table row by two column conditions

For instance, I have two tables in database, Users and Microposts. The Users table stores all the users and has two columns, id and name; the Microposts table stores the posts made by the Users and has three columns: id, post_content and user_id (These two tables, of course, have the timestamp as each entry is created). So basically what I want is have a view page that displays the information stored in Users (id and name) plus the last post created by the corresponding user.
One way I'm thinking of doing is to have it being processed right at the user view page (located in, for example, app/views/Users/index.html.erb). Since I'm probably going to loop through the Users table like this
<% #Users.each do |user| %>
id = user.id
<!-- Do such and such -->
<% end %>
and while looping through the Users table, use the user.id to get the latest post made by the user.
Second way is to basically implement such that the Users table has another column that store the latest post information and updates each time when a transaction is made to the database. So then when implementing the latest post can just be accessed as an attribute.
However, I don't really know which way is better nor how to implement either way...
Any suggestion?
Thanks in advance!
Edit:
Sorry, there is a typo. It's "two tables and one database"
Similar to the other answers but I wanted to add an important little piece that I feel is commonly overlooked. Including the association on the first call to the database.
# not sure the scale of your project but I would paginate #users
# by using includes you prevent the N+1 issues
<% #users.includes(:microposts).each do |user| %>
id = user.id
user.microposts.last
<% end %>
For some documentation on this:
http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations
class User
has_many :microposts
end
class Micropost
belong_to :user
end
# to get user's post
# for single user
#user.microposts
# for many users
#users.each do |user|
user.microposts.each do |post|
post.post_content
end
end
Your user has many microposts. So do the following on users view page i.e. app/views/Users/index.html.erb
<% #Users.each do |user| %>
id = user.id
last_post = user.microposts.last <!-- This will give you last post created by the user -->
<% end %>

Dropdown to view a page as different user roles while admin

I currently have a view simplified below...
<% if can? :manage, #task %>
Admin
<% elsif can? :update, #task %>
Moderator
<% elsif current_user %>
User
<% else %>
Not logged in
<% end %>
This view has a large number of fields that are wrapped in similar conditionals for each user and I currently have to log in and out of test accounts to check formatting.
I want to be logged in as an admin but have a dropdown to select whether the page is rendered as Admin or Moderator or User or Not logged in
I have some rough ideas of solutioning, but don't know which to follow...
Bake into cancan with an extra column on user that I can set from a navbar dropdown form
Create user specific methods
Allow a url parameter to request session view and render accordingly
Is there a best practice around this?
How about if you implemented something like the real/effective user dichotomy of Unix?
You're existing infrastructure is the 'real' user based on whatever authentication has occurred but you also associate an 'effective user' with each session.
The effective user starts out the same as the real user but can be changed to something else. Changing the effective user should be conditioned on the real user having admin rights.
Condition all your layout on the effective user and not on the real user.
Condition your 'change effective user' drop down on the real user.

How do I create a controller and action without a model?

I have several models:
Email
Letter
Call
All three belong to a model Campaign. And a Campaign has_many Contacts
I envision being able to see a schedule for Today by going to domain/schedule/today
What I'd like it to do would be to show all the Events (Email, Letter, Call) that have to happen today for each campaign.
I tried the following, but have some challenges in putting it into a controller versus into a View. There are many emails in campaign.
Email.days is the number of days from the contact.start_date that an email should be sent to the Contact.
ScheduleController <
def index
campaigns.each do |campaign| #goes through each campaign
for contacts in campaign.contacts
Email.find(:all).reject { |email| email.contact.start_date + email.days <= Date.now }
end
end
end
You're actually asking the wrong question.. Controllers aren't linked to any model fundamentally, they really display whatever you want. You can have a FooController that displays all the Bars and a DogController that gives info about cats..
To solve your problem:
You're not 'sharing' anything with
your view for it to display.
You're also putting the logic in the
wrong place, and you're not actually
fetching the campaigns from the
database..
In your controller you need to fetch the data from the DB:
def index
#campaigns = Campaign.all #share the list of campaigns with the view
end
In your view you display the campaign info..
<% for campaign in #campaigns %>
<!-- display info about the campaign -->
<% for contacts in campaign.contacts %>
<!-- contact level info and so on.. -->
<% end %>
<% end %>
There's much more to it, but hopefully this gets you pointed in the right direction.

Resources