Rails radar/forem forum engine - controlling access to certain forums or topics - ruby-on-rails

I'm using forem as forum engine and have it attached to my User model.
As part of my User model, I have "experts" and "novices" as the two different types of users.
If I only want to show the "expert" forum to "expert" users, what is the best way to control this access within forem?

You could try to modify the view under app/views/forem/forums/_forum.html.erb, enclosing all with this:
<% if forem_user.expert? %>
...
<% end %>
Note: if you don't have the forem views, you have to generate them with rails g forem:views.
Cheers!
EDIT:
The last version of Forem allows to redefine methods for permissions in your User model.
https://github.com/radar/forem/wiki/Authorization-System
So, in your case, you'd define the method can_read_forem_forum?(forum) and return true if the user is expert.

Related

Rails Model method that builds a string of links

I have a method on a model called Photo. I have it finding a selection of things from elsewhere in my app. All I need it to do at the end is to create a string of links that I can then output later on when the method is called on an instance.
My code is:
cars.map { |c| link_to(c.name, c) }.join(" AND ")
But i'm hitting this error:
undefined method `link_to' for #<Photo
Any ideas how to fix this?
link_to is a view helper which means it's only available in Rails views by default because it's a router / request concern.
If you specifically want to use link_to you have to include it or reference it directly.
See this SO answer
include ActionView::Helpers::UrlHelper
...
cars.map { |c| link_to(c.name, c) }.join(" AND ")
There are other ways of getting paths than using link_to that I would recommend you consider:
It's arguable that the Rails team would tell you to use UrlFor as the tip in that link suggests:
Tip: If you need to generate URLs from your models or some other place, then ActionController::UrlFor is what you're looking for. Read on for an introduction. In general, this module should not be included on its own, as it is usually included by url_helpers (as in Rails.application.routes.url_helpers).
UrlFor also allows one to access methods that have been auto-generated from named routes.
class User < ActiveRecord::Base
include Rails.application.routes.url_helpers
def base_uri
# named_route method that uses UrlFor
user_path(self)
end
end
User.find(1).base_uri # => "/users/1"
create your own concern to bring in route helpers via ActionMailer as this article suggests
As you may see if you scroll through other SO questions about including view helpers in models, there is pushback on using router and request -based methods outside of controllers and views because it violates the principles of MVC.
I think your use case can give you some peace of mind about this, but it's worth knowing the water is murky and some people may advise you otherwise.
The traditional Rails wisdom (and what I'm about to give you here) is that models should not be creating HTML. They also shouldn't have methods that return HTML. Creating HTML <a> tags should be done much closer to the user interface: in a view template or maybe in a view helper. One reason is that the particular way the hyperlink should be generated is a concern of the view. (Does it need a nofollow attribute? class attributes? This will change, even from one view to another.) And the model should not have any knowledge of these details.
When you do generate links in the views, then you have access to all the helpers such as link_to.
Instead, as I understand it, a model should be responsible for returning its own data. Maybe in your case that'd be an array of dicts of :label, :url. I.e., pure data that'd be easy to pass to link_to.
Hope that helps!

Adding new functionality to Spreecommerse

I am planning to launch a website that acts as a sort of courier service where clients ask my company to find a certain product(for example an action figure) from another country that is not available in their country.
Spreecommerce(including some extensions) offers almost all the functionality that I require.
Shopping Cart, Payment system, CMS, Open Authentication, Commenting system.
One important piece of functionality remains, that is an Enquiry system. with this system customers can request certain products they want.
The form they will use will have the following information:
Name Description
Price(optional)
Barcode(optional)
Category(Using the same taxon system as products)
Quantity
Images
Comments (using the spree-contrib/spree_comments)
My idea is that the user will be presented will have a form which when submitted the admin can view. The admin can view/modify the enquiry and respond using the commenting system. Once the item is located and confirmed, the admin would then create a product and add it to the user’s shopping cart which the user can finalise using the normal spree order check out system.
So my modifications to the system would be:
- Add the Enquiry form for both client and administrator(administrator can place enquiries in the name of the customer)
- Make Products private to the users who ordered them
- Disable the “products” page for users as each product is unique to each user
I am at the point of creating the Enquiry form page. I looked at the spreecommerse documentation and there doesn’t seem to be instructions on adding a new page and integrating it into the system. The documentation focuses more on modifying current pages.
Therefore I decided to view a project that implemented somewhat similar functionality and emulate what it did.
I went with spree-contrib/spree_static_content. So what I did was:
Create an enquiry migration using spree_products tables as guidelines with the following information:
enquiries table
enquiries_taxons table(Used for “categories”)
enquiries_variants table(Used for “image uploads”)
Created the following views under app/views/spree/admin (These views are mostly simplified versions of the product views) :
enquiries/_form.html.erb
enquiries/edit.html.erb
enquiries/index.html.erb
enquiries/new.html.erb
shared/_enquiries_sidebar_menu.html.erb
shared/_enquiry_tabs.html.erb
To add the menu item in the admin section:
app/overrides/add_enquiries_to_admin_main_menu.rb
Created an empty EnquiriesController that inherits from Admin::BaseController
Created an Enquiries model that inherits from Spree::Base and is loosely based on the Products model.
Things that I am confused about so far are:
How is CRUD handled?
Where are the spree.admin_{name}_url values being stored?
If there are any tutorials on how to properly create such functionality, it would also be greatly appreciated.
Hmm, why not use the Spree::Product model as a starting point? Just add custom attributes to that model/table. I suggest this because building your own tables and relations to variants and taxons seems like reinventing the wheel.
You've got a good start here. What you are missing so far is routes
spree.admin_{name}_url values being stored?
...you don't necessarily need to use the spree. namespace for routes if your controllers inherit from Spree::StoreController or Spree::AdminController. The Spree base controllers provide a bunch of useful CRUD logic. In your case you'd need a routes.rb file that looked something like this:
Rails.application.routes.draw do
mount Spree::Core::Engine, :at => '/'
end
Spree::Core::Engine.add_routes do
#public enquiries, e.g. that inherit Spree::StoreController
get 'enquiries', :to => 'enquiries#index', :as => :enquiries
end
Spree::Core::Engine.add_routes do
namespace :admin do
resources :enquiries
end
end
Hottip: check out the spree_scaffold gem. It makes stubbing out models/controllers/view/routes hella quick

Devise: logic using `admin_signed_in?` when Admin & User logged in on separate tabs in same browser

In my Rails 3.2 app there are two Devise models: User and Admin. I have a comment partial form that both can use to make comments on a Post. However, I have included conditional logic with the *_signed_in? helper provided by Devise so that a checkbox appears for admins that allows them to make their comment visible only to other admins. Form checkbox code:
- if admin_signed_in?
.pull-right
= label_tag :internal, "Private"
= f.check_box :internal
It's not a huge issue because it should never occur in production, but in development and staging I've noticed that if someone (tester, etc) is logged in as both an Admin and a User in different tabs on the same browser, the logic of my form doesn't work because (I guess?) those two tabs are using the same cookie/session info/whatever. The checkbox shows up on the User's form because the Admin is signed in on the other tab. It works fine if two different browsers are being used.
Is there a way to avoid this?
You may need to find or create a variable that can be used to determine if you're in the admin part of the site. A cheesy way would be to put a before filter in your admin controller(s) that sets an instance variable (#admin_site = true for example) then update your partial thus:
- if admin_signed_in? && #admin_site
.pull-right
= label_tag :internal, "Private"
= f.check_box :internal
However it's considered bad practice by some (Sandi Metz for example) to proliferate the instance variables sent to the view. Also, it's a good idea to pass parameters in to partials explicitly as locals rather than relying on instance variables. (This helps readability and makes it easier to share them in general).
The facade pattern can help here.
http://robots.thoughtbot.com/sandi-metz-rules-for-developers
Edit:
Since using the facade I tend to spurn helpers in general, but you could probably do something like this:
#app/helpers/application_helper.rb
module ApplicationHelper
def show_internal?
request[:controller].in? ['admin']
end
...
Assuming your admin actions are all in a controller called 'admin_controller'.
You can add more admin controllers if you have many, by adding to the array:
request[:controller].in? ['user_admin', 'product_admin']

Ruby on Rails (3) hiding parts of the view

I am working on a Ruby on Rails 3 web application.
I have a table named User with a coulmn named role. I am looking for the best way to hide parts of the view from users that have the "wrong" role for those parts of the view.
For example I want all users to be able to see the users index page, but i want only users with a role - admin to be able to edit other users.
So first I block the edit action using filter_by, but what I also want is make the edit button not to appear.
The current user is saved in the session, so checking the user role is very simple.
What I am asking, is there an easy way to do so besides the obvious if statement before each button I want to hide. I would think that rails would have an easy way to do this type of thing, I couldn't find one.
You may want to use Devise and CanCan.
https://github.com/plataformatec/devise
https://github.com/ryanb/cancan
Here is a RailCast tutorial
http://railscasts.com/episodes/192-authorization-with-cancan
if you wanted to clean it up a tiny bit you could write yourself an application helper:
def if_admin(user)
if(user.is_admin? && block_given?)
yield
return
end
end
then in your view you could write:
<% if_admin(#user) do %>
<some admin only html />
<% end %>

Rails user authorization

I am currently building a Rails app, and trying to figure out the best way to authenticate that a user owns whatever data object they are trying to edit.
I already have an authentication system in place (restful-authentication), and I'm using a simple before_filter to make sure a user is logged in before they can reach certain areas of the website.
However, I'm not sure the best way to handle a user trying to edit a specific piece of data - for example lets say users on my site can own Books, and they can edit the properties of the book (title, author, pages, etc), but they should only be able to do this for Books that -they- own.
In my 'edit' method on the books controller I would have a find that only retrieved books owned by the current_user. However, if another user knew the id of the book, they could type in http://website.com/book/7/edit , and the controller would verify that they are logged in, then show the edit page for that book (seems to bypass the controller).
What is the best way to handle this? Is it more of a Rails convention routing issue that I don't understand (being able to go straight to the edit page), or should I be adding in a before_find, before_save, before_update, after_find etc callbacks to my model?
check out the following gems:
cancan
devise
authlogic
and don't miss Ryan's great railscasts on the above
this will give access to anyone who changes the value in the address bar
#book = Book.find(params[:id])
but if you go through the association of the logged on user rails (ActiveRecord) will automatically update the sql query
#book = current_user.books.find(params[:id])
of course this assumes that your books table has a user_id column
You may need an authorization plugin. I had some experience use this plugin a while back. This article also has an overview:
You might also take a look at Declarative Authorization
Hey I have recently done this myself. The easiest way to do this is to have the edit feature display on the page but incase it in a method such as the following:
<%if current_user %>
<% if current_user.id == wishlist.user_id %>
<div id="text3"><%= link_to 'Edit', edit_wishlist_path(#wishlist) %></div><br />
<%end%>
<%end%>
Is this what you were hoping for?

Resources